题目连接: 数字游戏
第一种做法:
递推。
这个题我wa了估计有10次了,难受。
这个题应该是dp问题,可是我一眼看过去,以为是深搜,结果跑20层树果然超时,想了很长那个时间没办法对这个二叉树进行剪枝,最后找了还是递推出来的,等会休息会再拿dp来做。
首先我们很有必要给这个数组排个序。
然后…
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 21;
int num[maxn];
int main()
{
int n;
while(cin>>n)
{
for(int i=0;i<n;i++)
{
cin>>num[i];
}
sort(num,num+n);
int sum=num[0];
if(num[0]>1)
{
cout<<1<<endl;
continue;
}
if(num[0]+1<num[1])
{
if(num[0]) cout<<"2"<<endl;
else cout<<"1"<<endl;
continue;
}
for(int i=1;i<n;i++)
{
//cout<<i<<" !!!"<<num[i]<<endl;
sum+=num[i];
//cout<<sum<<" "<<num[i+1]<<endl;
if(sum+1<num[i+1])
{
break;
}
}
if(n==1 && num[0]==1)
{
cout<<"2"<<endl;
continue;
}
cout<<sum+1<<endl;
}
return 0;
}
第二种做法:
深度优先搜索。这是个超时的做法,同学不要模仿=_=。因为有20个数字,相当于实现一个全排列,构造一颗状态树,然后把所有的节点的值存起来标记,每一个节点的值就是可以构造出来的数,最后一个一个找出来就行,这个也是刘汝佳书数里说的回溯-生成法。
题目给的数组长度是20以内,所以用正确的搜索剪枝说不定也能过,应该是我没找到方法,毕竟递推和dp可以解决的问题规模远远大于搜索,不至于才给20。
#include<iostream>
#include<algorithm>
#include<cstring>
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
const int maxn = 1e5+5;
int num[25];
int judge[25]; //表示在深搜的过程中,该值是否被访问过
int vis[maxn]; //将出现的结果保存
int n,sum; //sum用来保存搜索过程中的更新的和值 ;
int dfs(int ith);
int main()
{
while(cin>>n)
{
memset(judge,0,sizeof(judge)); //0表示没访问过,1表示访问过
memset(vis,0,sizeof(vis));
for(int i = 0;i < n;++i) cin>>num[i];
sort(num , num+n);
for(int i = 0;i < n;++i) //对数组实现全排列,保存树的每个节点的sum值
{
if(judge[i]) continue;
sum += num[i];
vis[sum] = 1;
judge[i] = 1;
dfs(1);
judge[i] = 0;
sum -= num[i];
}
for(int i = 1;i < maxn;i++)
{
if(!vis[i])
{
cout<<i<<endl;
break;
}
}
}
return 0;
}
int dfs(int ith)
{
if(ith == n)
{
return 0;
}
for(int i = 0;i < n;i++)
{
if(judge[i]) continue;
sum += num[i];
vis[sum]=1;
if(!vis[sum-1]) return 0;
judge[i]=1;
dfs(ith+1);
judge[i]=0;
sum -= num[i];
}
return 0;
}
第三种做法:
动态规划。