您的位置:首页 > 其它

【暑假】[深入动态规划]UVAlive 4794 Sharing Chocolate

2016-03-30 17:20 459 查看
UVAlive 4794 Sharing Chocolate

题目:
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=12055
思路:

设d[S][r][c]表示形如r*c的矩形是否可以划分为S中的子集,10表示可否。

转移方程:

d[S][r][c] = d[S0][r0][c] || d[S0][r][c0]

优化:

首先注意到S r c三者知二求一,所以将状态优化为d[S][x]表示有短边x的矩形是否可以分为S的子集,长边==sum(S)/x ,这样恰好迎合了另外一个优化——只计算r*c==S的状态。

代码:

1 #include<iostream>
2 #include<cstring>
3 using namespace std;
4
5 const int maxn = 15+5;
6 const int maxw = 100 + 5;
7
8 int d[1<<maxn][maxw],vis[1<<maxn][maxw];
9 int sum[1<<maxn];
10 int kase=0;
11
12 inline int bitcount(int x) { return x==0?0:bitcount(x/2)+(x&1); }
13
14 int dp(int s,int x) {
15     if(vis[s][x]==kase) return d[s][x];  //记忆化搜索
16     vis[s][x]=kase;
17     if(bitcount(s)==1) return d[s][x]=1;  //搜索边界
18
19     int& ans=d[s][x];
20     int y=sum[s]/x;                     //根据s与x计算y
21     for(int s0=(s-1)&s;s0;s0=(s0-1)&s) {  //枚举子集 //一刀
22         int s1=s-s0;                   //划分成两个子集
23         if(sum[s0]%x==0 && dp(s0,min(x,sum[s0]/x)) && dp(s1,min(x,sum[s1]/x)) ) return ans=1;  //是纵向一刀
24         if(sum[s0]%y==0 && dp(s0,min(y,sum[s0]/y)) && dp(s1,min(y,sum[s1]/y)) ) return ans=1;  //抑或横向一刀
25         //如果有一种切法 分成的两个子矩形YES的话那么该矩阵为YES
26     }
27
28     return ans=0;
29 }
30
31 int main() {
32     ios::sync_with_stdio(false);
33     int n,x,y;
34     int A[maxn];
35     memset(vis,0,sizeof(vis));
36
37     while(cin>>n && n) {
38         cin>>x>>y;
39         for(int i=0;i<n;i++) cin>>A[i];
40
41         int full=(1<<n)-1;
42         for(int s=0;s<=full;s++){  //离线计算集合s之和
43          sum[s]=0;
44          for(int j=0;j<n;j++) if(s&(1<<j)) sum[s] += A[j];
45         }
46
47         int ans;
48         if(sum[full]!=x*y || sum[full]%x!=0) ans=0;  //面积相等且形如x*y
49         else
50          ans=dp(full,min(x,y));
51
52         cout<<"Case "<<++kase<<": ";
53         cout<<(ans? "YES" : "No")<<"\n";
54     }
55     return 0;
56 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: