传送门:POJ1014
题意:给你1-6六个数,分别有不一定的数量,问你能不能凑成和相等的两部分。
其实这个题真的很水啊,真的真的很水啊,可是月赛的时候愣是让三个人TLE的一晚上,想尽办法剪枝,又剪成了WA。。最后赛完发现是回溯的问题。。。这题根本不用回溯。。带上回溯必定超时,不回溯的原因是:dfs的时候已经保证了每次加入一个新数时不能超过sum/2,所以只需要一口气搜到底就好了,如果这次拼不成,就算再回溯也肯定拼不成,这里做个假设要拼凑的数为sum/2==30,那么前18用越大的数来拼越好(优先级6>5>4...),因为较小的数要留下来处理边界情况,后12数越小边界情况越有可能处理成功,因此如果回溯用另外一些小的数去拼凑这里的18,后面就更不可能拼成了。
理解不了也可以感性思考一下,因为我们是去dfs拼凑两部分之一,那么这一堆里没有的数就是要扔给另一堆的,你这一堆用这些数都拼不成,在回溯的时候把这些数扔给另一堆,那另一堆肯定也拼不成啊。。
写这篇博客来纪念一下一晚上的TLE吧。。
下面是正确代码:
#include<stdio.h>
#define n 6
int sum;
int num[6],k=0,flag;
int dfs(int s)//s是已经凑出来的数的和
{
if(s==sum||flag)
{
flag=1;
return 0;
}
for(int i=5;i>=0;i--)
{
if(num[i]&&(s+i+1)<=sum)
{
num[i]--;
dfs(s+(i+1));
if(flag)
return 0;
}//千万不要回溯
}
}
int main()
{
int i;
while(~scanf("%d",&num[0]))
{
flag=0;
sum=0;
k++;
for(i=1;i<6;i++)
scanf("%d",&num[i]);
for(i=0;i<6;i++)
{
sum+=num[i]*(i+1);
}
if(sum==0)
break;
printf("Collection #%d:\n",k);
if(sum%2==0)
{
sum/=2;
dfs(0);
if(flag)
printf("Can be divided.\n");
else
printf("Can't be divided.\n");
}
else
{
printf("Can't be divided.\n");
}
printf("\n");
}
}