【POJ2248、LOJ#10021】 Addition Chains

事先预警:由于我太蒻了,本做法只能在POJ、LOJ等小数据(N<=100)平台上通过,在UVa(洛谷)上大数据并不能通过

戳我获得更好的观看效果

本题不用看,爆搜就是了,但是纯爆搜显然会爆时间,所以要加上一些剪枝
我们来看一下一些常用的剪枝(什么剪枝,其实这么多枝砍掉了,树都没了)
1.最优化剪枝:不存在的,本题求输出方案
2.优化搜索顺序:由于是SPJ,我们对于每个位置上的数字倒着枚举,容易搜索到答案
3.可行性剪枝:需用到数学方法,但是我不会,由于不加该剪枝也能过,所以不讲

最重要的: 卡常

剩下的思路见代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
inline int read(){
	char chr = getchar();	int f = 1,ans = 0;
	while(!isdigit(chr)) {if(chr == '-') f = -1;chr = getchar();}
	while(isdigit(chr))  {ans = (ans << 3) + (ans << 1);ans += chr - '0';chr = getchar();}
	return ans* f ;
}
void write(int x){
	if(x < 0) putchar('-'),x = -x;
	if(x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
int n,m;
int ff=0;
int a[50];
int book[500];
void dfs(int x,int m){//当前找到第n个数 
	if(x==m+1){
		if(a[x-1]==n)//由于每个位置我们都用尽量大的数,第一次搜索到的就是答案
			ff=1;//标记答案找到了
		return;//返回
	}
	for(int i=n;i>=a[x-1]+1;i--){//枚举第x个位置的数值
		if(ff) return;
		int fff=0;
		for(int j=1;j<=x-1;j++){//判断能否由前面的数字构成
			if(i-a[j]>=1 && book[i-a[j]]){
				fff=1;
				break;
			}
		}
		if(fff){
			book[i]=1;
			a[x]=i;
			dfs(x+1,m);//往下搜
			book[i]=0;//回溯
			if(ff) return;
		}
	}
}

int main(){
	n=read();
	while(n!=0){
		if(n==1){
			write(1),puts("");
			n=read();
			continue;
		}
		ff=0;
		a[1]=1;
		book[1]=1;
		int i;
		for(i=2;i;i++){//枚举长度
			ff=0;
			memset(book,0,sizeof(book));//记录某个数是否搜索到过
			book[1]=1;//book[1]=1;
			dfs(2,i);
			if(ff)//退出
				break;
		}
		for(int j=1;j<=i;j++)
			write(a[j]),putchar(' ');
		puts("");
		n=read();
	}
	return 0;
}
posted @ 2018-08-24 12:23  zheng_liwen  阅读(322)  评论(0编辑  收藏  举报
/*去广告*/