• 划分问题(01背包)


    Description

    给定一个正整数的集合A={a1,a2,….,an},是否可以将其分割成两个子集合,使两个子集合的数加起来的和相等。例A = { 1, 3, 8, 4, 10} 可以分割:{1, 8, 4} 及 {3, 10}

    Input

    第一行集合元素个数n  n <=300 第二行n个整数

    Output

    如果能划分成两个集合,输出任意一个子集,否则输出“no”

    Sample Input

    5
    1 3 8 4 10

    Sample Output

    3 10

    解题思路

    • 本题可转化为一个容量为sum/2的背包,是否存在一组物品可以刚好装满背包的问题。
    • 用dp[i][j]来表示前i个物品是否能恰好装满容量为j的背包,即可得递推公式:
      dp[i][j] = if(dp[i-1][j] || dp[i-1][j-v[i]]) // j>=v[i]
    • 路径输出:倒序输出,若前i个物品能恰好装满j容量的背包,并且前i-1个物品不能,则说明第i个物品必须装入背包,即:
      if(j >= a[i] && dp[i][j] && !dp[i-1][j]) printf("%d ", a[i]);
      然后再让容量j-=a[i]继续输出剩余物品

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    int a[305];
    
    int main () {
        int n, sum = 0;
        cin >> n;
        for(int i = 1; i <= n; ++i) {
            scanf("%d", a+i);
            sum += a[i];
        }
        if(sum%2) { // 和为奇数直接输出no
            cout << "no";
            return 0;
        }
        sum/=2;
        int dp[n+5][sum+5];
        memset(dp, 0, sizeof dp);
        dp[1][0] = 1; // 这里不能少
        dp[1][a[1]] = 1; // 同上
    
        for (int i = 2; i <= n; ++i) { // 枚举物品
            for (int j = 0; j <= sum; ++j) { // 枚举容量
                if(dp[i-1][j]) {
                    dp[i][j] = 1;
                }
                if(j >= a[i] && dp[i-1][j-a[i]]) {
                    dp[i][j] = 1;
                    //cout << "debug:" << i << " " << j;
                }
            }
        }
        if(!dp[n][sum]) { // 没有找到可行方案
            printf("no");
            return 0;
        }
    
        // 路径输出,倒序
        for (int i = n, j = sum; i >= 1&&j>0; --i) {
            if(j >= a[i] && dp[i][j] && !dp[i-1][j]) {
                printf("%d ", a[i]);
                j -= a[i];
            }
        }
        return 0;
    }
    
  • 相关阅读:
    USACO Section 2.2 Subset Sums
    九度 1399 名侦探柯南
    九度 1416 猴子吃坚果
    pch文件的使用(原作者太逗了)
    线程同步
    extern "c"
    进程与线程
    排序算法代码汇总
    Linux Shell 常用命令与目录分区的学习总结 (开始学习linux)
    堆和栈
  • 原文地址:https://www.cnblogs.com/knightoflake/p/14686898.html
Copyright © 2020-2023  润新知