• [Poj 1015] Jury Compromise 解题报告 (完全背包)


    题目链接:http://poj.org/problem?id=1015

    题目:

    题解:

    我们考虑设计DP状态(因为这很显然是一个完全背包问题不是吗?)

    dp[j][k]表示在外层循环到i时,选了j个人,此时辩方总分和控方总分差值为k的时,辩方和控方的总分的和的最大值

    dp[j][k+a[i]-b[i]] = max (dp[j][k + a[i] - b[i]] , dp[j][k] + a[i] + b[i])

    因为是完全背包,所以我们需要写一个search函数判断当前转移的状态是否已经选过了i,这样我们需要记录一个d[j][k]数组表示在dp[j][k]的状态是选哪一个人转移过来的,这恰好也是题目要求我们处理出来的

    题解其实就是上述部分了

    题外话:

    我们考虑不写那个search函数,然后把j这一维倒序循环,根据《算法竞赛进阶指南》,这样的做法是可以的,但是笔者尝试之后还做不到,碰到的问题就是假设dp[j][k+a[i]-b[i]]被dp[j-1][k]转移得到,此时我们可以确定dp[j-1][k]这个状态没有选择i这个人。

    但是在之后的循环中,dp[j-1][k]可能会被再次更新,我们要是只是统计答案的话这并没有什么影响,但是我们在d数组回溯的时候就会得到错误的转移,因为dp[j-1][k]可能被i更新,于是d[j-1][k]变成了i。补充:但是在我的AC代码里,显然是可以避免这种情况的,因为dp[j-1][k]不可能再被更新

    除此之外,我发现i循环放在最外面是不行的。这是为什么?若是有读者知道请在评论区留言。

    AC代码(加了search函数)

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    int n,m,fix,time;
    int a[201],b[201],dp[201][801],d[201][801],id[201];
    inline int read()
    {
        char ch=getchar();
        int s=0,f=1;
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
        return s*f;
    }
    bool search(int j,int k,int i)
    {
        while (j&&d[j][k]!=i)
        {
            int o=d[j][k];
            k-=a[o]-b[o];
            j--;
        }
        if (j) return false;
        return true;
    }
    int main()
    {
        while (1)
        {
            n=read();m=read();
            if (!n) break;
            for (int i=1;i<=n;i++)
            {
                a[i]=read();b[i]=read();
            }
            memset(dp,-1,sizeof(dp));
            memset(d,0,sizeof(d));
            fix=m*20;
            dp[0][fix]=0;
            for (int j=1;j<=m;j++)
                for (int k=0;k<=fix<<1;k++)
                    if (dp[j-1][k]>=0)
                    {
                        for (int i=1;i<=n;i++)
                            if (dp[j-1][k]+a[i]+b[i]>dp[j][k+a[i]-b[i]]&&search(j-1,k,i))
                            {    
                                dp[j][k+a[i]-b[i]]=dp[j-1][k]+a[i]+b[i];
                                //if (j==3&&k+a[i]-b[i]==57&&k==58) printf("sdfs%d
    ",d[j-1][k]);
                                d[j][k+a[i]-b[i]]=i;
                                //if (j==2&&k+a[i]-b[i]==58) printf("%d
    ",i);
                            }
                    }
            int k,div;
            for (int i=0;i<=fix;i++)
                if (dp[m][fix-i]!=-1||dp[m][fix+i]!=-1) {k=i;break;}
                //printf("%d
    ",k); 
            div=dp[m][fix-k]>dp[m][fix+k]?(fix-k):(fix+k);
            printf("Jury #%d
    ",++time);
            printf("Best jury has value %d for prosecution and value %d for defence:
    ",(dp[m][div]+div-fix)/2,(dp[m][div]-div+fix)/2);
            int r=div;
            for (int i=1;i<=m;i++)
            {
                id[i]=d[m-i+1][r];
                r-=a[id[i]]-b[id[i]];
            }
            sort(id+1,id+1+m);
            for (int i=1;i<=m;i++) printf(" %d",id[i]);
            printf("
    
    ");
        }    
         return 0;
    }
  • 相关阅读:
    Android进程的优先级说明
    Android的有序广播和无序广播(解决安卓8.0版本之后有序广播的接收问题)
    Android开发中常用Dialog(普通弹窗&时间选择器&日历选择器)
    Android的显示意图和隐式意图总结
    Android的启动模式
    怎么评论一段php语言文本单词one-hot编码的健壮性
    python 基础知识,解决模板引擎实现原理流程
    SQL----EXISTS 关键字EXISTS基本意思
    omcat启动Publishing failed with multiple errors
    AngularJs directive详解及示例代码
  • 原文地址:https://www.cnblogs.com/xxzh/p/9561460.html
Copyright © 2020-2023  润新知