zoukankan      html  css  js  c++  java
  • 【暑假】[深入动态规划]UVAlive 4794 Sharing Chocolate

    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")<<"
    ";
    54     }
    55     return 0;
    56 }
  • 相关阅读:
    Android Studio 打包生成apk
    找水王
    关于搜狗输入法的用户体验评价
    c语言函数的嵌套使用和矩阵运算
    人月神话阅读笔记02
    第一阶段冲刺意见评论汇总
    高校表白App-团队冲刺第十天
    高校表白App-团队冲刺第九天
    高校表白App-团队冲刺第八天
    人月神话阅读笔记01
  • 原文地址:https://www.cnblogs.com/lidaxin/p/4750821.html
Copyright © 2011-2022 走看看