题意:给x*y(x,y<100)的巧克力,将其分为n块(n<15),给定这n块的面积,均为整数,每次划分只能横着切或者纵着切成2部分,判断能否切除满足题意的巧克力
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n;
int x,y;
int area[20];
int Sum[1<<20]; // pre-handling area of all pieces
bool dp[110][1<<20];
bool vis[110][1<<20];
// calculate the number of bits with a value of 1
int bit_count(int x) {
int cnt = 0;
for(int i = 0;i < 20;i++) {
if(x&(1<<i)) cnt++;
}
return cnt;
}
// memorized search
bool DP(int x,int s) {
if(vis[x][s]) return dp[x][s];
vis[x][s] = true;
// ensure that x*y equals to Sum[s] before you enter DP function
int y = Sum[s] / x;
// special case, special judge
if(bit_count(s) == 1) {
return dp[x][s] = true;
}
// enumerate subset of s
for(int s0 = ((s-1)&s);s0;s0=((s0-1)&s)) {
if(Sum[s0]%x==0&&Sum[s0^s]%x==0&&DP(min(x,Sum[s0]/x),s0)&&DP(min(x,Sum[s0^s]/x),s0^s)) return dp[x][s] = true;
if(Sum[s0]%y==0&&Sum[s0^s]%y==0&&DP(min(y,Sum[s0]/y),s0)&&DP(min(y,Sum[s0^s]/y),s0^s)) return dp[x][s] = true;
}
return dp[x][s] = false;
}
int main() {
int kase = 1;
while(scanf("%d",&n) && n) {
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
memset(Sum,0,sizeof(Sum));
scanf("%d%d",&x,&y);
for(int i = 0;i < n;i++) scanf("%d",&area[i]);
int ALL = (1<<n) - 1;
for(int s = 0;s <= ALL;s++) {
for(int i = 0;i < n;i++) {
if(s&(1<<i)) Sum[s] += area[i];
}
}
if(x*y == Sum[ALL] && DP(min(x,y),ALL)) printf("Case %d: Yes\n",kase++);
else printf("Case %d: No\n",kase++);
}
return 0;
}