poj.1416

枚举+剪枝,读懂题目意思后就是简单的枚举了,题目要求将一个数字分解成多个数字,并将这些数字的和与目标数字作比较。比较结果有三种情况:

1)error,所有组合的数字都比目标数字大

2)rejected,所有组合的数字中,存在多于一个不超过目标数字且最大的组合数字

3)sum=part1+part2+part3的形式,除开上述两种情况

这里还要注意一下几点:

1)注意题目中附带了一句:若输入的两数字相等。则不cut,其实这是第三种请况,但由于比较特殊,所以可以独立判别,增加速度。

2)注意在cut的过程中,有一点要明白:20022,若将其cut成这样的数字2 , 0  ,0 ,2,2,和cut成这样的数字2,0,02,2结果的和是相等的,也就是说0数字开头也要考虑中(起先没有考虑这个),这在rejected的判别中尤其要注意

3)在用深搜枚举时,减枝的关键在于将大于目标数字的情况剪掉,这样就只留下小于等于目标数字的组合数字,同时也便于判断是否是第一种情况。

下面是代码:164K+0MS

#include <stdio.h>
#include <stdlib.h>
#include <stack>
#define Max 10
using namespace std;
int Time;
int source[Max];
int target[Max];
int ttarget[Max];
int sn,tn;
int rlen;
int slen;
int Sum;
stack<int> Sta;
bool Is_error;
int Power(int n){
	int temp=1;
	for(int i=1;i<=n;i++)
		temp*=10;
	return temp;
}
void dfs(int rindex,int num,int Count){
	if(num==slen){
		Is_error=false;
		if(Count>Sum){
			rlen=rindex;
			for(int i=0;i<rlen;i++)
				ttarget[i]=target[i];
			Time=1;
			Sum=Count;
		}
		else if(Count==Sum)
			Time++;
		return ;
	}
	if(Count+source[num]<=tn){
	target[rindex]=source[num];
	dfs(rindex+1,num+1,Count+source[num]);
	}
	for(int i=num+1;i<slen;i++){
		int fuck=Power(i-num);
		int temp=0;
		for(int j=num;j<=i;j++){
			temp+=fuck*source[j];
			fuck/=10;
		}
		target[rindex]=temp;
		if(Count+temp>tn)
			continue;
		dfs(rindex+1,i+1,Count+temp);
	}
}

int main(){
	while(scanf("%d%d",&tn,&sn)){
		if(sn==0)
			break;
		if(sn==tn){
			printf("%d %d\n",sn,tn);
			continue;
		}
		int temp=sn;
		while(temp>0){
			Sta.push(temp%10);
			temp/=10;
		}
		int pivot=1;
		while(!Sta.empty()){
			source[pivot++]=Sta.top();
			Sta.pop();
		}
		slen=pivot;
		Sum=0;
		Is_error=true;
		dfs(0,1,0);
		if(Is_error)
			printf("error\n");
		else{
			if(Time>1)
				printf("rejected\n");
			else{
			printf("%d",Sum);
			for(int i=0;i<rlen;i++)
				printf(" %d",ttarget[i]);
			printf("\n");
			}
		}
	}
	return 0;
}
			
	


 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值