zoukankan      html  css  js  c++  java
  • UVa 1009 Sharing Chocolate (数位dp)

    题目链接:

      https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3540

    题目大意:

      给一块长x,宽y的巧克力,和一个数组A={a1, a2, …,an},问能否经过若干次切分后,得到面积分别为a1,a2,…an的n块巧克力。每次切分只可以选择一块巧克力,将其分为两半,如下图,3×4的巧克力经过切分后,可以得到面积分别为6,3,2,1的巧克力。

    解题思路:

      假设能得到n块小巧克力,考虑切分的过程,第一次切分后巧克力被分为两部分,最终结果中的任一快巧克力a[i]要么来自第一部分,要么来自第二部分,即两部分分别对应一个A的子集。那么枚举A的子集A0,另A1=A-A0,如果能找到当前巧克力的一种切分方式,让第一部分能分成A0对应的小巧克力,第二部分分成A1对应的小巧克力,则找到了一组合法的解。

      定义dp状态如下,dp[x][S](S是二进制表示的集合)表示边长分别为x, S对应面积/x的巧克力能否切分成S对应集合,若能则为1,否则为0。考虑到边长x*y=面积,因此只保留一个边长,另一边可以求出来。

      此代码中枚举子集的方法是数位dp的一个技巧。

    参考代码:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 #define N 16
     6 
     7 bool f[105][1<<N];
     8 bool vis[105][1<<N];
     9 int A[N], sum[1<<N];
    10 int cntbit(int x)
    11 {
    12     int ret = 0;
    13     while(x) ret += x&1, x >>= 1;
    14     return ret;
    15 }
    16 
    17 bool dp(int x, int cur)//cur用二进制表示当前集合
    18 {
    19     if(vis[x][cur] == 1) return f[x][cur];
    20     vis[x][cur] = 1;
    21     bool &ans = f[x][cur];
    22     int y = sum[cur]/x;
    23     if(cntbit(cur) == 1)
    24     {
    25         vis[x][cur] = 1;
    26         return ans = true;
    27     }
    28     for(int s0 = (cur-1)&cur; s0; s0 = (s0-1) & cur)//枚举子集的方法
    29     {
    30         int s1 = cur-s0;
    31         if(sum[s0]%x == 0 && dp(min(x, sum[s0]/x), s0) && dp(min(x, sum[s1]/x), s1))
    32             return ans = 1;
    33         if(sum[s0]%y == 0 && dp(min(y, sum[s0]/y), s0) && dp(min(y, sum[s1]/y), s1))
    34             return ans = 1;
    35     }
    36     return ans = 0;
    37 }
    38 
    39 int main()
    40 {
    41     int n, x, y, cas = 1;
    42     while(~scanf("%d", &n), n)
    43     {
    44         scanf("%d %d", &x, &y);
    45         for(int i = 0; i < n; i++) scanf("%d", &A[i]);
    46 
    47         memset(sum, 0, sizeof(sum));
    48         for(int i = 0; i < (1<<n); i++)
    49             for(int j = 0; j < n; j++) if(i&(1<<j)) sum[i] += A[j];
    50 
    51         int d = (1<<n)-1;
    52         if(sum[d] != x*y)
    53         {
    54             printf("Case %d: No
    ", cas++);
    55             continue;
    56         }
    57 
    58         memset(vis, 0, sizeof(vis));
    59         bool ans = dp(min(x, y), d);
    60         printf("Case %d: ", cas++);
    61         puts(ans ? "Yes" : "No");
    62     }
    63     return 0;
    64 }
  • 相关阅读:
    (一)Kafka0.8.2官方文档中文版系列入门指南
    Hbase TTL(Time To Live)详解
    java源码学习详解Object类
    设计模式详细解读简单工厂方法模式
    (二)Kafka0.8.2官方文档中文版系列API
    Scala对象相等性判断
    scala中跳出循环的3种方法
    wpf 中借助 Grid 实现随着 Form 大小变化而按比例自动改变宽度或高度。
    static and cache
    约定编程之 Dictionary 的 String 类型的 Key
  • 原文地址:https://www.cnblogs.com/beisong/p/4663663.html
Copyright © 2011-2022 走看看