poj 1416 组合数(DIY碎纸机)

题意:给定两个数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;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值