題目來源:[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了