题意很简单,给你一块长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"); } }