UVALive 4794 Sharing Chocolate(状压,枚举子集)
n的规模可以状压,f[x][y][S]表示x行,y列,S集合的巧克力能否被切割。
预处理出每个状态S对应的面积和sum(S),对于一个合法的状态一定满足x*y=sum(S),实际上只有两个变量是独立的。
而且有x,y等效与y,x,那么这里取max(x,y)。
转移的时候枚举S的非空真子集,横着切或者竖着切。
边间是到达一个合法的x,y,S,其中S中只有一个元素。
复杂度O(x*3^n)
#include<bits/stdc++.h> using namespace std; const int Mx = 101,Mxs = 1<<16; bool meo[Mx][Mxs]; int sumA[Mxs]; int vis[Mx][Mxs], clk;//避免memset int a[16],n; int ss[17]; bool dfs(int x,int y,int S) { if(x<y) swap(x,y); if(vis[x][S] == clk) return meo[x][S]; vis[x][S] = clk; if(sumA[S] != x*y) return meo[x][S] = false;//这里其实可以dfs外就判断,之后转移一定保证合法 if(*lower_bound(ss,ss+17,S)== S) return meo[x][S] = true; for(int S0 = S&(S-1); S0 ; S0 = (S0-1)&S){//忽略不在S中的1 if(sumA[S0]%x == 0){ int y0 = sumA[S0]/x; if(dfs(x,y0,S0) && dfs(x,y-y0,S^S0)) return meo[x][S] = true; } if(sumA[S0]%y == 0){ int x0 = sumA[S0]/y; if(dfs(x0,y,S0) && dfs(x-x0,y,S^S0)) return meo[x][S] = true; } } return meo[x][S] = false; } //#define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif for(int i = 0; i < 17; i++){ ss[i] = 1<<i; } while(scanf("%d",&n),n){ int x,y; scanf("%d%d",&x,&y); for(int i = 0; i < n; i++) scanf("%d",a+i); int mxs = (1<<n); for(int S = 0; S < mxs; S++){ sumA[S] = 0; for(int i = 0; i < n; i++){ if(S>>i&1) sumA[S] += a[i]; } } clk++; printf("Case %d: %s\n",clk,dfs(x,y,mxs-1)?"Yes":"No"); } return 0; }