题意:给定两个数n和m,现要把m拆开成若干个数(比如m为123,可以拆成1、23或者12、3或者1、2、3),求所有拆法中和小于n的最大值。其中有三点要求:1、如果n与m相同,则不必拆分;2、如果任何拆法都会使得和大于n,输出“error”;3、如果有多于1种拆法取得最大值,则输出“rejected”。
思路:实际上就是暴搜,求出所有拆分的可能。拿第一组数据(50 12346)来说:12345为5位数,则拆分方法分为将其1分为5、1分为4……1分为1(注意细节,1分为1贡献了一个WA)。而5位数有4个空位,那么将空位编号为1,2,3,4,求出所有组合的方案即可。例如C4,0表示1分为1,C4,1表示1分为2。具体来说,C4,2的一种组合2,4表示在第2和第4个空断开,也将原数拆分成12、34、6.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 10
char s[8],t[8];
int used[N],res[N],n,max,maxd,ans[8],flag,len;
void update(int d){
int i,j,num,temp,a[8];
num = temp = 0;
for(i=0,j=0;i<len;i++){
temp = temp*10+t[i]-'0';//temp提取出每个拆出来的数
if(j<d && i+1 == res[j]){
num += temp;//num是此种拆分的加和
if(num > n)
return ;
a[j] = temp;
temp = 0;
j++;
}
}
a[d] = temp;
num += temp;
if(num<=n && num > max){
max = num;
maxd = d;
flag = 0;
for(i = 0;i<=d;i++)//记录结果
ans[i] = a[i];
}else if(num == max)
flag = 1;
}
void dfs(int n,int end,int d,int now){//求组合Cn,d,end是组合数的个数
int i;
if(d == end){
update(d);
return ;
}
for(i = now+1;i<=n;i++)
if(!used[i]){
res[d] = i;
used[i] = 1;
dfs(n,end,d+1,i);
used[i] = 0;
}
}
int main(){
freopen("a.txt","r",stdin);
while(scanf("%s %s",s,t) && strcmp(s,"0")){
int i,j;
flag = max = 0;
if(!strcmp(s,t)){//不拆分的情况
printf("%s %s\n",s,t);
continue;
}
n = atoi(s);
len = strlen(t);
for(i = 0;i<len;i++){//i从0开始,贡献了一次wa。(由101 100这组数据得到的启发)
memset(used,0,sizeof(used));
dfs(len-1,i,0,0);//暴搜
}
if(max == 0)//最大值没有更新,也就是无法拆分
printf("error\n");
else if(flag)//最大值多于1个
printf("rejected\n");
else{
printf("%d",max);
for(i = 0;i<=maxd;i++)
printf(" %d",ans[i]);
printf("\n");
}
}
return 0;
}