藍橋杯之帶分數(全排列+暴力)

小白tree發表於2020-10-16

題目連結:

http://oj.ecustacm.cn/problem.php?id=1426

Description

100 可以表示為帶分數的形式:100 = 3 + 69258 / 714。
還可以表示為:100 = 82 + 3546 / 197。
注意特徵:帶分數中,數字1~9分別出現且只出現一次(不包含0)。
類似這樣的帶分數,100 有 11 種表示法。

Input

從標準輸入讀入一個正整數N (N<1000*1000)

Output

程式輸出該數字用數碼1~9不重複不遺漏地組成帶分數表示的全部種數。

Sample Input
樣例輸入1

100

樣例輸入2

105

Sample Output
樣例輸出1

11

樣例輸出2

6

分析:

(1)直接暴力全排列
(2)全排列基礎上對每種排列方式,用2個隔板m、n隔出3個數x,y,z,將數按照 x + y / z == N 進行判斷即可

#include<iostream>
#include<algorithm>
using namespace std;

int main()
{
	int N;
	cin >> N;
	int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	int  count = 0;
	bool flag = false;
	
	// 儘量只讓全排列只排1次,否則時間損耗太大,所以將全排列放在外迴圈
	do {
		for (int m = 1; m <= 7; m++)
		{
			for (int n = m + 1; n <= 8; n++)
			{
				// 以m,n為分割,1 ~ m 構成的是sum_head,
				// m+1~n 構成的分子是sum_mid,n+1 ~ 9構成的是sum_tail
				int sum_head = 0;
				for (int j = 1; j <= m; j++)
					sum_head = sum_head * 10 +a[j];
				//cout << sum_head << endl;
				int sum_mid = 0;
				for (int j = m + 1; j <= n; j++)
					sum_mid = sum_mid * 10 + a[j];
				//cout << sum_head << endl;
				int sum_tail = 0;
				for (int j = n+1; j <= 9; j++)
					sum_tail = sum_tail * 10 +a[j];
				//cout << sum_tail << endl;

				// 如果取餘為0才可下一步,畢竟都是整數,sum_mid / sum_tail會直接截斷小數部分,也可能等於N,造成不準確
				if (sum_mid  % sum_tail == 0)
					if (sum_head + sum_mid / sum_tail == N)
						count++;
			}
		}
	// 注意我的a陣列是啊a[0]到a[9],則需要從a[1]到a[9]進行全排列
	} while (next_permutation(a+1, a + 10));
	
	cout << count << endl;

	return 0;
}