• POJ 1015 Jury Compromise (记录路径的背包问题)


    (点击此处查看原题)

    题意

    为了审判某一个人,需要在n个人当中选出m个人组成陪审团,n个人中每个人都有作为起诉方的价值p和作为辩护方的价值d,为了保证公平性,要求m个人作为起诉方的价值之和P和作为辩护方的价值之和D满足 |P-D| 最小,在此基础上,要求P+D最大。最后求P,D以及选出的作为陪审团的m个人并且这m个人的字典序最小。

    解题思路

    看懂题目后,很容易就可以发现这是一个背包问题,即是否选择第i个人当作陪审团,不过所选人数必须是m个,相比于01背包问题,这个题目限制了选择的人数,那么我们就用dp[j][j] 表示当前选择了i个人,这i个人的P-D = j 的情况下,P+D的最大值,因为数组下标不能取负数,那我们加上一个修正值fix = 20 * m 即可

    不过网上很多的写法都是有问题的,正确的解法应该这样枚举:选的人-->选的人作为第几个人-->P-D的值,枚举选的人的时候,我们从小开始枚举,这样一来就可以使得所选的人的字典序最小,记录路径的方法就用vector path[i][j] 记录对应dp[i][j]的情况下的所选的人

    (其实这个应该算是比较常规的DP问题增加了一些套路,比如限制总数和记录路径)

    代码区

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<queue>
    #include<string>
    #include<fstream>
    #include<vector>
    #include<stack>
    #include <map>
    #include <iomanip>
    
    #define bug cout << "**********" << endl
    #define show(x, y) cout<<"["<<x<<","<<y<<"] "
    #define LOCAL = 1;
    using namespace std;
    typedef long long ll;
    const ll inf = 1e18 + 7;
    const ll mod = 1e9 + 7;
    const int Max = 2e2 + 10;
    
    int n, m;
    int sub[Max], add[Max];
    int dp[25][805];
    vector<int> path[25][805];
    
    int main()
    {
    #ifdef LOCAL
    //    freopen("input.txt", "r", stdin);
    //    freopen("output.txt", "w", stdout);
    #endif
        int kCase = 0;
        while (scanf("%d%d", &n, &m) != EOF && n + m)
        {
            for (int i = 1, p, d; i <= n; i++)
                scanf("%d%d", &p, &d), sub[i] = p - d, add[i] = p + d;
    
            int fix = 20 * m;
    
            for (int i = 0; i <= m; i++)
                for (int j = 0; j <= 2 * fix; j++)
                    path[i][j].clear(), dp[i][j] = -1;
            dp[0][fix] = 0;
    
            for (int i = 1; i <= n; i++)
                for (int j = m - 1; j >= 0; j--)
                    for (int k = 0; k <= 2 * fix; k++)
                        if (dp[j][k] >= 0 && dp[j][k] + add[i] > dp[j + 1][k + sub[i]])
                        {
                            dp[j + 1][k + sub[i]] = dp[j][k] + add[i];
                            path[j + 1][k + sub[i]] = path[j][k];
                            path[j + 1][k + sub[i]].push_back(i);
                        }
            int dis;
            for (dis = 0; dis <= fix; dis++)
            {
                if (dp[m][fix - dis] >= 0 || dp[m][fix + dis] >= 0)
                    break;
            }
            int S = dp[m][fix - dis] > dp[m][fix + dis] ? fix - dis : fix + dis;
            int P = (dp[m][S] + S - fix) / 2;
            int D = (dp[m][S] - S + fix) / 2;
    
            printf("Jury #%d
    ", ++kCase);
            printf("Best jury has value %d for prosecution and value %d for defence:
    ", P, D);
            for (int i = 0; i < m; i++)
            {
                printf("%d%c", path[m][S][i], i == path[m][S].size() - 1 ? '
    ' : ' ');
            }
            printf("
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    异地协作,A地上传jar包到B地服务器上传速率慢
    linux一行命令查杀进程
    maven项目创建.m2文件夹
    模态框传递参数
    测试身份证信息
    jenkins:邮件配置良心之作
    python:不错的python编程核心思想
    jenkins:忘记密码怎么办
    docker:如何查看容器的挂载目录
    JavaScript + PHP 实现刷新继续保持倒计时的按钮
  • 原文地址:https://www.cnblogs.com/winter-bamboo/p/11574402.html
Copyright © 2020-2023  润新知