题目来源:[NWPU][2014][TRN][4]搜索 I题
http://vjudge.net/contest/view.action?cid=49557#problem/I
作者:npufz
题目:给出一个不上升的正整数序列,再给定一个值SUM,在给定的那列数字中找出所有的和为SUM的数字组合,然后对所有组满足和为SUM的组合,进行不升序排列,然后按照从起始位一次降低的情况输出所有的组合
例如:SUM=4 有 10个数字,:4,4,3,3,2,2,2,1,1,1
输出为:4;
3+1;
2+2;
2+1+1;
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
int vis[15]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
int jl[15]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
bool flag;
int cs;
void print(int sum)
{ bool fir;
fir=true;
int j;
if(cs==1)
{ j=0;
if(flag)
{printf("Sums of %d:\n",sum);flag=false;}
for(int i=0;i<15;i++)
{ if(vis[i]!=-1)
jl[j++]=vis[i];
if(fir==true&&vis[i]!=-1)
{
printf("%d",vis[i]);fir=false;
}
else if(vis[i]!=-1) printf("+%d",vis[i]);
}
cout<<endl;cs=-1;
}
else
{ bool flag2=false ,flag1=true;j=0;
int m=0;
for(int i=0;i<15;i++)
{
if(vis[i]!=-1)
{ if(vis[i]>jl[m]) {flag1=false;break;}
if (vis[i]<jl[m]) break;
m++;
}
}
for(int i=0;i<15&&flag1;i++)
{
if(vis[i]!=-1)
{ if(vis[i]!=jl[j])
{jl[j]=vis[i];flag2=true;}
j++;
}
}
if(flag2&&flag1) { flag2=false;
for(int i=0;i<15;i++)
{
if(fir==true&&vis[i]!=-1)
{
printf("%d",vis[i]);fir=false;
}
else if(vis[i]!=-1) printf("+%d",vis[i]);
}
cout<<endl;
}}}
bool dfs(int sum, int num ,int i,int sum1,int a[] )
{
if(sum>=sum1 &&i<=num)
{ if(sum==sum1) print(sum);
vis[i]=a[i];
dfs(sum,num,i+1,sum1+a[i],a);
vis[i]=-1;
dfs(sum,num,i+1,sum1,a);
vis[i]=-1;
}
else return true;
}
using namespace std;
int main()
{ int a[15],sum,num,i;
while(scanf("%d%d",&sum,&num),num)
{ for(i=0;i<num;i++)
scanf("%d",&a[i]);
flag=true;cs=1;
dfs(sum,num,0,0,a);
if(flag) printf("Sums of %d:\nNONE\n",sum);
}
return 0;
}
反思:主要是对深搜理解的有点不对劲,在控制递归的条件上有失误,在改正之后,发现输出是个大问题,我程序的解空间是一个很每个元素加进去与不加进去的一个树,复杂度很高不说,一旦所给的序列中出现重复的元素,那没就会搜索到很多的重解,去重复是个很关键的东西,一开始想的太简单了,有漏洞,就WA了,改了后就A了