题意:给出一个长宽确定的矩形,每次可以沿一条直线把它分割成两块长宽都为整数的矩形,问能否通过多次操作得到n块面积分别为a1,a2...an的矩形。
与分蛋糕的生日快乐有点像。记忆化搜索、枚举子集。
由于n很小可以直接状压,s表示需要得到的巧克力的状态集合。
因为每次所有的要得到的巧克力面积和等于r*c,可以根据这个剪枝,同时把状态f[r][c][s]变成二维f[r][s]。
然后发现如果写return 1,2;最后会返回2。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=17,maxs=(1<<15)+10; int n,r,c,tot[maxs]; int f[110][maxs]; int aa;char cc; int read() { aa=0;cc=getchar(); while(cc<'0'||cc>'9') cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa; } bool ok(int r,int s) { if(f[r][s]) return f[r][s]-1; if(s==(s&(-s))) return f[r][s]=2,1; int x,y,c=tot[s]/r; for(x=(s-1)&s;x;x=(x-1)&s) { y=s-x; if(tot[x]%c==0&&ok(r*tot[x]/tot[s],x)&&ok(r*tot[y]/tot[s],y)) return f[r][s]=2,1; if(tot[x]%r==0&&ok(r,x)&&ok(r,y)) return f[r][s]=2,1; } return f[r][s]=1,0; } int main() { n=read();int tt=0; while(n) { r=read();c=read(); int x; memset(tot,0,sizeof(tot)); memset(f,0,sizeof(f)); for(int i=1;i<=n;++i) tot[1<<(i-1)]=read(); for(int i=1;i<(1<<n);++i) { x=(i&(-i)); if(i==x) continue; tot[i]=tot[x]+tot[i^x]; } printf("Case %d: ",++tt); if(r*c!=tot[(1<<n)-1]||!ok(r,(1<<n)-1)) printf("No "); else printf("Yes "); n=read(); } return 0; }