2013蓝桥杯C初赛求带分数(涉及全排列问题)

题目标题: 100 可以表示为带分数的形式:100 = 3 + 69258 / 714 
还可以表示为:100 = 82 + 3546 / 197 
注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。 类似这样的带分数,100 有 11 种表示法。

以下代码列举所有表示法:

#include<stdio.h>
#include<string.h>

/*检查某个数是否出现重位的情况,可以与nKill整合,但这儿单独列出*/
bool checkNum(int n){
	char arr[]="x123456789";
	do{
		if(arr[n%10]<='9'){
			arr[n%10]='x';
		}else{
			return false;
		}
		n/=10;
	}while(n!=0);
	return true;
}

/*去除数组中已出现过的数字*/
void nKill(int n,char * arr){
	do{
		//标记已被选
		arr[n%10]='#';
		n/=10;
	}while(n!=0);
}

/*交换两个数*/
void change(char *a,char *b){
	char tmp;
	tmp=*a;
	*a=*b;
	*b=tmp;
}

/*字符串逆序*/
void start2End(char * arr){
	int len=strlen(arr),i;
	for(i=0;i<len/2;i++){
		change(arr+i,arr+len-i-1);
	}
}

/*集合全排列*/
bool nextArr(char * arr,int len){
	int i,j;
	//寻找第一个左边比右边小的数
	for(i=len-1;i>0;i--){
		if(arr[i]>arr[i-1]){
			break;
		}
	}
	//如果找不到波动了,也就意味着找完了
	if(i==0){
		return false;
	}
	i--;
	//寻找右边第一个比i处值大的
	for(j=len-1;j>i;j--){
		if(arr[j]>arr[i]){
			break;
		}
	}
	//交换
	change(arr+i,arr+j);
	//倒序
	start2End(arr+i+1);
	return true;
}

/*字符串转数字*/
int str2N(char *arr,int len){
	int count=0,i=0;
	while(i!=len){
		count=count*10+(arr[i++]-'0');
	}
	return count;
}

/*遍历寻找填入/的位置*/
bool insert(char *res,int len,int result,int n){
	int i,a,b;
	for(i=len/2;i<len;i++){
		a=str2N(res,i);
		b=str2N(res+i,len-i);
		//printf("%d/%d\n",a,b);
		if(a/b==result && a%b==0){
			printf("%d+%d/%d\n",n,a,b);
			return true;
		}
	}
	return false;
}

/*计算核心 作者:天之*/
void fun(int n,int result){
	//1~9的全排列
	char arr[]="#123456789";
	char res[10];
	nKill(n,arr);
	int i=0,j=0;
	char ch;
	while((ch=arr[i++])!='\0'){
		if(ch!='#'){
			res[j++]=ch;
		}
	}
	res[j]='\0';
	do{
		insert(res,j,result,n);
	}while(nextArr(res,j));
}

void main(){
	int i,n,tmp;
	scanf("%d",&n);
	for(i=1;i<n;i++){
		tmp=n-i;
		if(checkNum(tmp)){
			fun(n-i,i);
		}
	}
}

 

点赞