zoukankan      html  css  js  c++  java
  • CH5E07 划分大理石【多重背包】

    5E07 划分大理石 0x5E「动态规划」练习
    描述
    有价值分别为1..6的大理石各a[1..6]块,现要将它们分成两部分,使得两部分价值之和相等,问是否可以实现。其中大理石的总数不超过20000。

    输入格式
    有多组数据!
    所以可能有多行
    如果有0 0 0 0 0 0表示输入文件结束
    其余的行为6个整数

    输出格式
    有多少行可行数据就有几行输出
    如果划分成功,输出Can,否则Can't

    样例输入
    4 7 4 5 9 1
    9 8 1 7 2 4
    6 6 8 5 9 2
    1 6 6 1 0 7
    5 9 3 8 8 4
    0 0 0 0 0 0
    样例输出
    Can't
    Can
    Can't
    Can't
    Can

    题意:

    有六种石子,价值是1-6,每种石子有一个数量。现在想把他们平分为价值相等的两堆,问是否可行。

    思路:

    首先统计一下总的价值,如果价值是奇数,肯定是不行的。

    如果价值是偶数,就是一个多重背包问题。

    所以先把每种石头用二进制拆分,价值即是价值又是重量。最后看dp[mid]是否等于mid就可以了。

     1 //#include <bits/stdc++.h>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<stdio.h>
     6 #include<cstring>
     7 #include<vector>
     8 #include<map>
     9 #include<set>
    10 
    11 #define inf 0x3f3f3f3f
    12 using namespace std;
    13 typedef long long LL;
    14 
    15 int stone[10], dp[300010];
    16 int num[300010], cnt;
    17 
    18 
    19 void split(int n, int v)
    20 {
    21     int x = 1, tmp = 0;
    22     while(tmp <= n){
    23         num[cnt++] = x * v;
    24         x *= 2;
    25         tmp += x;
    26     }
    27     x = n - tmp;
    28     if(x){
    29         num[cnt++] = x * v;
    30     }
    31 }
    32 
    33 
    34 int main(){
    35     while(true){
    36         int sum = 0;
    37         for(int i = 1; i <= 6; i++){
    38             scanf("%d", &stone[i]);
    39             sum += stone[i] * i;
    40             //dp[i][0] = true;
    41         }
    42         if(sum == 0){
    43             break;
    44         }
    45 
    46         if(sum % 2){
    47             printf("Can't
    ");
    48             continue;
    49         }
    50 
    51         cnt = 0;
    52         for(int i = 1; i <= 6; i++){
    53             split(stone[i], i);
    54         }
    55         memset(dp, 0, sizeof(dp));
    56         int mid = sum / 2;
    57         for(int i = 0; i < cnt; i++){
    58             for(int j = mid; j >= num[i]; j--){
    59                 dp[j] = max(dp[j], dp[j - num[i]] + num[i]);
    60             }
    61         }
    62 
    63         if(dp[mid] == mid){
    64             printf("Can
    ");
    65         }
    66         else{
    67             printf("Can't
    ");
    68         }
    69     }
    70     return 0;
    71 }
  • 相关阅读:
    poj 2411 Mondriaan's Dream 骨牌铺放 状压dp
    zoj 3471 Most Powerful (有向图)最大生成树 状压dp
    poj 2280 Islands and Bridges 哈密尔顿路 状压dp
    hdu 3001 Travelling 经过所有点(最多两次)的最短路径 三进制状压dp
    poj 3311 Hie with the Pie 经过所有点(可重)的最短路径 floyd + 状压dp
    poj 1185 炮兵阵地 状压dp
    poj 3254 Corn Fields 状压dp入门
    loj 6278 6279 数列分块入门 2 3
    VIM记事——大小写转换
    DKIM支持样本上传做检测的网站
  • 原文地址:https://www.cnblogs.com/wyboooo/p/9778638.html
Copyright © 2011-2022 走看看