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
",clk,dfs(x,y,mxs-1)?"Yes":"No");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jerryRey/p/4847041.html