#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
int M,N,a[10005],vis[10005],co=0;
bool hasFind = false;
void dfs(int sum,int start)
{
if(sum==M)
{
hasFind=true;
for(int i=0;i<N;i++)
if(vis[i]==1)
{
if(co==0)
{
printf("%d",a[i]);
co++;
}
else
printf(" %d",a[i]);
}
}
for(int i=start;i<N&&hasFind==false;i++)
{
if(vis[i]==1)
continue;
if(sum+a[i]>M)
break;
sum+=a[i];
vis[i]=1;
dfs(sum,i);
sum-=a[i];
vis[i]=0;
}
}
int main()
{
memset(vis,0,sizeof(vis));
scanf("%d%d",&N,&M);
for(int i=0;i<N;i++)
scanf("%d",&a[i]);
sort(a,a+N);
dfs(0,0);
if(hasFind==false)
printf("No Solution");
return 0;
}
最后一个点被卡时间了,我的想法是给输入的数列从小到大排个序,然后从最小的数开始深搜,一旦找到某个解,他一定就是最优解,因为
我是从最小的值开始深搜的,每次深搜找到的也是次小的值,所以一定能保证在有多个序列解的情况下,第一个找出来的序列,序列前部与
其他次优解的前部相等的情况下,第一个不等的值一定是最小的,也就达到了题目的要求。
但是这种解法在最坏情况,也就是无解的情况时间复杂度为O(2^N),每个节点都有选与不选两种情况。。。因此时间复杂度为2^N次,剪
枝只能改变较好情况下的时间复杂,但最坏情况,也就是无解的情况,时间复杂度过大。
到这里,我就考虑一下最坏情况 大概是哪些情况,试了一下当所有的输入值加起来 还没有 M大时,我们就不需要去做深搜了,因为不管怎么
加,都是无解的。。在代码里加入这一段判定之后就过了。。。
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
int M,N,a[10005],vis[10005],co=0;
bool hasFind = false;
void dfs(int sum,int start)
{
if(sum==M)
{
hasFind=true;
for(int i=0;i<N;i++)
if(vis[i]==1)
{
if(co==0)
{
printf("%d",a[i]);
co++;
}
else
printf(" %d",a[i]);
}
}
for(int i=start;i<N&&hasFind==false;i++)
{
if(vis[i]==1)
continue;
if(sum+a[i]>M)
break;
sum+=a[i];
vis[i]=1;
dfs(sum,i);
sum-=a[i];
vis[i]=0;
}
}
int main()
{
int temp=0;
memset(vis,0,sizeof(vis));
scanf("%d%d",&N,&M);
for(int i=0;i<N;i++)
{
scanf("%d",&a[i]);
temp+=a[i];
}
if(temp<M)
printf("No Solution");
else
{
sort(a,a+N);
dfs(0,0);
if(hasFind==false)
printf("No Solution");
}
return 0;
}