这题切巧克力,首先看见这题数据很小,n小于等于15,可以直接压缩状态,全集就是(1<<n)-1,然后取他的子集分析
首先要把每个集合内的巧克力的面积和求出来,sum[s]=sigma(a[i]),s&(1<<i)==1;
状态转移方程是dp(s,min(r,sum[s]/r))分成两个子状态dp(s0,min(r,sum[s0]/r))和dp(s1,min(r,sum[s1]/r)),s0+s1=s;sum[s0]+sum[s1]=sum[s]
如果两个子状态都为真,那么总的状态就为真。
dp的边界时bitcount(s)==1,return 1;如果所有分割都不成立,那么return 0
#include<iostream> #include<cstdio> #include<cctype> #include<cstdlib> #include<cmath> #include<algorithm> #include<cstring> #include<string> #include<vector> #include<queue> #include<map> #include<set> #include<sstream> #include<stack> using namespace std; #define MAX 50005 typedef long long LL; const double pi=3.141592653589793; const int INF=1e9; const double inf=1e20; const double eps=1e-6; int a[16],sum[1<<16],vis[1<<16][105],d[1<<16][105]; int bitcount(int x){ return (x==0)?x:bitcount(x/2)+(x&1); } int dp(int s,int x){ if(vis[s][x]) return d[s][x]; vis[s][x]=1; if(bitcount(s)==1) return d[s][x]=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&&dp(s0,min(x,sum[s0]/x))&&dp(s1,min(x,sum[s1]/x))) return d[s][x]=1; if(sum[s0]%y==0&&dp(s0,min(y,sum[s0]/y))&&dp(s1,min(y,sum[s1]/y))) return d[s][x]=1; } return d[s][x]=0; } int main(){ int n,kase=0; while(cin>>n&&n){ kase++; int x,y; scanf("%d%d",&x,&y); memset(sum,0,sizeof(sum)); memset(vis,0,sizeof(vis)); for(int i=0;i<n;i++) scanf("%d",&a[i]); for(int s=1;s<(1<<n);s++){ for(int i=0;i<n;i++){ if(s&(1<<i)) sum[s]+=a[i]; } } int all=(1<<n)-1; int ans; if(sum[all]!=x*y) ans=0; else ans=dp(all,min(x,y)); if(ans) printf("Case %d: Yes\n",kase); else printf("Case %d: No\n",kase); } return 0; }