Jury Compromise

Jury Compromise

有n对数,每对数由((d_i,p_i))组成,现在要求选出m对数,(sum)表示对这m对数中的元素累加,在(|sum d_i-sum p_i|)最小的前提下,保证(sum d_i+sum p_i)最大,,输出(sum d_i,sum p_i),(1<=n<=200, 1<=m<=20,d_ileq 20,p_ileq 20)

对于绝对值问题,常采取去绝对值的方法,如波浪,就是采取递增填排列,忽略了绝对值的影响,或者是直接可以进行转移,如making grade。

此处肯定要以处理到哪一对数为阶段,两个阶段之间存在影响,故无法去绝对值,但是注意到数据范围很小,于是a我们可以直接转移绝对值,于是不难想到(f[i][j][k])表示考虑到第i对数,已经选了j对数,(sum d_i-sum p_i)为k的最大的(sum d_i+sum p_i),于是不难有转移

[f[i][j][k]=max(f[i-1][j][k],f[i-1][j-1][k-(d_i-p_i)]+d_i+p_i) ]

边界:(f[0][0][0]=0),其余负无限大

答案:(f[n][m][d]),(|d|)尽可能小

而且注意到第一维可以丢掉,类似背包,再进行倒序枚举即可。

参考代码:

未压维

#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
using namespace std;
int dp[201][21][901],pre[201][21][901],
    d[201],p[201];
template<class free>
il free Max(free,free);
il void print(int,int,int);
int main(){
    int n,m,tot(0);
    while(scanf("%d%d",&n,&m),n,m){
        for(ri int i(1);i<=n;++i)
            scanf("%d%d",&d[i],&p[i]);
        memset(dp,-127,sizeof(dp)),memset(pre,0,sizeof(pre));
        dp[0][0][450]=0;
        for(ri int i(1),j,k;i<=n;++i){
            for(k=0;k<=900;++k)dp[i][0][k]=dp[i-1][0][k];
            for(j=1;j<=m;++j)
                for(k=0;k<=900;++k)
                    if(k-(d[i]-p[i])>=0&&k-(d[i]-p[i])<=900){
                        dp[i][j][k]=dp[i-1][j][k];
                        if(dp[i-1][j-1][k-(d[i]-p[i])]+d[i]+p[i]>dp[i][j][k])
                            dp[i][j][k]=dp[i-1][j-1][k-(d[i]-p[i])]+d[i]+p[i],pre[i][j][k]=1;
                    }
        }int ans(0);
        for(ri int i(450);i<=900;++i)
            if(dp[n][m][i]>=0||dp[n][m][900-i]>=0){
                if(dp[n][m][i]>dp[n][m][900-i])ans=i;
                else ans=900-i;
                break;
            }
        printf("Jury #%d
Best jury has value %d for prosecution and value %d for defence:
",
               ++tot,dp[n][m][ans]+ans-450>>1,dp[n][m][ans]-(dp[n][m][ans]+ans-450>>1));
        print(n,m,ans),putchar('
'),putchar('
');
    }
    return 0;
}
il void print(int a,int b,int c){
    if(!a||!b||!c)return;
    if(pre[a][b][c]){
        print(a-1,b-1,c-(d[a]-p[a]));
        printf("%d ",a);
    }
    else print(a-1,b,c);
}
template<class free>
il free Max(free a,free b){
    return a>b?a:b;
}

压了维

#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
using namespace std;
bool pre[201][21][901];
int d[201],p[201],dp[21][901];
void print(int,int,int);
int main(){
    int n,m,i,j,k,tot(0);
    while(scanf("%d%d",&n,&m),n&&m){
        memset(pre,0,sizeof(pre));
        memset(dp,-127,sizeof(dp));
        dp[0][450]=0;
        for(i=1;i<=n;++i){
            scanf("%d%d",&d[i],&p[i]);
            for(j=m;j;--j)
                for(k=0;k<=900;++k){
                    if(k-(d[i]-p[i])<0||k-(d[i]-p[i])>900)continue;
                    if(dp[j-1][k-(d[i]-p[i])]+d[i]+p[i]>dp[j][k])
                        dp[j][k]=dp[j-1][k-(d[i]-p[i])]+d[i]+p[i],pre[i][j][k]|=true;
                }
        }
        for(j=450;j<=900;++j)
            if(dp[m][j]>=0||dp[m][900-j]>=0){
                if(dp[m][j]>dp[m][900-j])i=j;
                else i=900-j;
                break;
            }j=dp[m][i]+i-450>>1,k=dp[m][i]-j;
        printf("Jury #%d
Best jury has value %d for prosec"
               "ution and value %d for defence:
",++tot,j,k),
            print(n,m,i),putchar('
'),putchar('
');
    }
    return 0;
}
void print(int a,int b,int c){
    if(!a||!b)return;
    if(pre[a][b][c])
        print(a-1,b-1,c-(d[a]-p[a])),
            printf(" %d",a);
    else print(a-1,b,c);
}

原文地址:https://www.cnblogs.com/a1b3c7d9/p/10917485.html