问题描述(蓝桥杯练习系统可提交)
100 可以表示为带分数的形式:100 = 3 + 69258 / 714。
还可以表示为:100 = 82 + 3546 / 197。
注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。
类似这样的带分数,100 有 11 种表示法。
输入格式
从标准输入读入一个正整数N (N<1000*1000)
输出格式
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!
样例输入1
100
样例输出1
11
样例输入2
105
样例输出2
6
本人解题思路(还有其他):枚举法
既然是由不同数字组成的,那么可以初始化一个数组[1,2,3,4,5,6,7,8,9],然后对这个数组进行全排列。对于前面每一个排列组合,把它切成三份,a,b,c,然后再去拿去a,b,c的每一种组合数。
比如,此时的全排列数组为[3,6,9,2,5,8,7,1,4], 首先为a取值,假如a = 3(当然a还可以取36,369...,前提是a不能大于等于n), 那么b,c的取值可以这样取,从3之后开始,在他们任意之间插入“/”, “/”前面的就是b,后面的就是c,在a,b,c得每一次取值都去验证a+b/c==n, 是,就+1.
当获取到一个排列时(我是用的next_permutation()函数获取得),可得
当a=3时,b,c可取6/9258714,69/258714,692/58714...
当a=36时,b,c可取9/258714,92/58714,925/8714...
当a=369时,b,c可取2/58714,25/8714,258/714..(如果n=100,那么此时a的取值是错误的)
......
细节:c不能为0
#include <iostream> #include <algorithm> using namespace std; // 拿数字 int toNum(int *data,int s, int e) { int ret = 0; for (int i = s; i <= e; i++) { ret = ret*10+data[i]; } return ret; } int main() { int data[10]; int n, ans,s,e,a,b,c,flag; while(~scanf("%d", &n)) { for (int i = 0; i < 10; i++) data[i] = i; ans = 0; do { s = e = 1; while(1) { a = toNum(data, s, e);// 确定a得值 if (a >= n) break; // 当a截取得值大于n时,说明已经是错误得,直接进行下一个排列 // 让分数线从左往右一位数一位数的移动 for (int i = e+1; i < 10-1; i++) {// 必须保证c有一位数,不然分母为零,所以i<10-1 b = toNum(data, e+1, i); c = toNum(data, i+1, 9); if (b%c != 0) continue; if (a+b/c==n) ans++; } e++;// 移动 } }while(next_permutation(data+1, data+10)); // 全排列 cout << ans << endl; } return 0; }
此处无声胜有声。