题目大意:给出一块面积为x*y的巧克力,每次操作可以沿着一条直线把一块巧克力切割成两块长宽均为整数的巧克力,问能否经过切割得到n块面积分别为a1,a2,...,an的巧克力
解题思路:用sum数组将n块巧克力的所有状态记录下来,然后枚举所有状态
因为n块巧克力的面积刚好为n*m,所以只要所需的状态的面积不等于当前剩余巧克力所能切割一次的面积,那么就无法完成切割了。
解释上面那句话:当剩余巧克力进行横向切割,所需状态为statu时,如果sum[statu] % x != 0就表示切割失败,因为要得到所需的状态的面积,如果按横向切割必然会有多余的巧克力存在,这样多余的巧克力就浪费了,就和n块巧克力面积刚好为n*m相矛盾了,按y轴切割的情况也一样
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 16
#define maxm 110
int p[maxn], sum[1 << maxn], vis[1 << maxn][maxm], dp[1 << maxn][maxm];
int bitcount(int S) {
return S == 0 ? 0 : bitcount(S/2) + S % 2;
}
int dfs(int S, int x) {
if(vis[S][x])
return dp[S][x];
vis[S][x] = 1;
int &ans = dp[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 && dfs(S0,min(sum[S0]/x,x)) && dfs(S1,min(sum[S1]/x,x)))
return ans = 1;
if(sum[S0] % y == 0 && dfs(S0,min(sum[S0]/y,y)) && dfs(S1,min(sum[S1]/y,y)))
return ans= 1;
}
return ans = 0;
}
int main() {
int N, x, y, mark = 1;
while(scanf("%d", &N) == 1 && N) {
scanf("%d%d",&x, &y);
for(int i = 0; i < N; i++)
scanf("%d",&p[i]);
for(int i = 0; i < (1 << N); i++) {
sum[i] = 0;
for(int j = 0; j < N; j++)
if(i & (1 << j))
sum[i] += p[j];
}
int ans, ALL = (1 << N) - 1;
if(sum[ALL] != x * y)
ans = 0;
else {
memset(vis,0,sizeof(vis));
ans = dfs(ALL,min(x,y));
}
printf("Case %d: %s\n",mark++, ans ? "Yes":"No");
}
return 0;
}