历届试题 带分数(全排列+枚举)

问题描述
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


最近看了一些ACM的书要吐血了,这题刚看的时候居然有点蒙,现设a+b/c==n, 问题出在n上,就是我想n那么大枚举完a再考虑b, c肯定要超时怎么行呢!然而别忘了一点,就是说n可以很大,可以一直变,但是有一点不变,那就是1~9的排列数,你这些其实只能从1~9的排列里面选出数来,比如随便167385492,那么就是说a取前面几个数,b接着取几个数,剩下的给c,现在的情况就是变得跟n没多大关系了,然后根据限制条件(1)a<n(2)b<c(3)b%c==0可以筛除一大部分数据,就是枚举的时候注意一下技巧。

# include <cstdio>
# include <cmath>
# include <algorithm>
using namespace std;
int n, s[10];
int main(){
	int i, j, k, a, b, c, ans;
	scanf("%d", &n);
	ans=0;
	for(i=0; i<=8; i++){
		s[i]=i+1;
	}
	do{
		a=0;
		for(i=0; i<=6; i++){
			a=10*a+s[i];
			if(a>=n){
				break;
			}
			b=0;c=0;
			for(j=i+1; j<=(8-i+1)/2+i; j++){//因为b>c所以b取剩下的数目至少一半。
				b=b*10+s[j];
			}
			for(j=(8-i+1)/2+i+1; j<=8; j++){//b取完后剩下的给c 
				c=c*10+s[j];
			}
			if(b>c&&b%c==0&&a+b/c==n){
				ans++;
			}
		    for(k=(8-i+1)/2+i+1; k<=7; k++){//动态改变b,c 
		    	b=b*10+s[k];c=c-s[k]*(int)pow(10, 8-k);
		    	if(b%c==0&&a+b/c==n){
		    		ans++;
				}
			}
		}
	}while(next_permutation(s, s+9));
	printf("%d", ans);
	return 0;
}

你可能感兴趣的:(枚举,算法,蓝桥杯,排列,OJ)