题意很简单,给你一块长x宽y的大巧克力,再给你n个面积为ai的小巧克力,问你能不能再若干次切割把大巧克力切割成n个巧克力,一次切割,必须把一块巧克力变成两块,不能切弯的,能就输出Yes,不能输出No
因为n的大小为16,所以可以用二进制表示当前剩下的巧克力集合,如果剩下巧克力集合的子集模当前的x或者y为0,可以进行下一步递推,直到只剩下一块巧克力或者不能不能操作为止,可用记忆化搜索。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=16;
const int maxw=110;
int d[1<<maxn][maxw],vis[1<<maxn][maxw];
int A[maxw],sum[1<<maxn];
int bitcount(int x)
{
return x==0?0:bitcount(x/2)+(x&1);//之前写+x&1,wa的我精神奔溃,位运算优先级低!!
}
int dp(int s,int x)
{
if(vis[s][x])
return d[s][x];
vis[s][x]=1;
int& ans=d[s][x];
if(bitcount(s)==1)
return ans=1;
int y=sum[s]/x;
for(int s0=(s-1)&s;s0;s0=(s0-1)&s)
{
int s1=s-s0;
if(sum[s0]%x==0&&dp(s0,min(x,sum[s0]/x))&&dp(s1,min(x,sum[s1]/x)))
return ans=1;
if(sum[s0]%y==0&&dp(s0,min(y,sum[s0]/y))&&dp(s1,min(y,sum[s1]/y)))
return ans=1;
}
return ans=0;
}
int main()
{
int Kase=0;
int n,x,y,i,j;
while(~scanf("%d",&n)&&n)
{
int ans=0;
scanf("%d%d",&x,&y);
for(i=0;i<n;i++)
scanf("%d",&A[i]);
for(i=0;i<(1<<n);i++)
{
sum[i]=0;
for(j=0;j<n;j++)
if(i&(1<<j))
sum[i]+=A[j];
}
memset(vis,0,sizeof(vis));
int ALL=(1<<n)-1;
if(sum[ALL]==x*y)//如果大巧克力面积不等于所有小巧克力面积之和,肯定是No
ans=dp(ALL,min(x,y));
printf("Case %d: %s\n",++Kase,ans?"Yes":"No");
}
}