码迷,mamicode.com
首页 > 其他好文 > 详细

Jury Compromise

时间:2019-06-08 15:03:07      阅读:99      评论:0      收藏:0      [点我收藏+]

标签:初始   mes   promise   价值   分析   --   循环   ace   span   

POJ

题意:有\(N\)对数,每对数由\((a_i,b_i)\)组成,现在要求选出\(M\)对数,在\(|\sum a_i-\sum b_i|\)最小的前提下,保证\(\sum a_i+\sum b_i\)最大.输出\(\sum a_i,\sum b_i\)以及任意一种方案.\(1<=n<=200,1<=m<=20,a_i,b_i≤20.\)

分析:把\(N\)对数看作物品数量,\(M\)对数看作背包容量,\(|a_i-b_i|\)看作物品体积之一,\(a_i+b_i\)看作物品价值.设\(f[i][j][k]\)表示前i个物品,选出了j个物品,体积为k,所能够获得的最大价值.

\(f[i][j][k]=max(f[i][j][k],f[i-1][j-1][k-(a[i]-b[i])]+a[i]+b[i])\).

可以直接把第一维滚掉,优化空间复杂度.

注意到k这一维可能是负数,所以我们把数组下标从\([-400,400]\)挪到\([0,800]\),所以初始化\(f[0][400]=0\),其余负无穷.

题目要求方案,设\(pre[i][j][k]\)表示前i个物品,选出了j个物品,体积为k的方案是(1)否(0)存在.每次可以更新\(f\)数组时,\(pre[i][j][k]=1\),最后递归输出即可.

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
inline int read(){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
int a[205],b[205],f[25][805],pre[205][25][805];
inline void print(int x,int y,int z){//输出方案
    if(!x||!y)return;
    if(pre[x][y][z])print(x-1,y-1,z-(a[x]-b[x])),printf(" %d",x);
    else print(x-1,y,z);
}
int main(){
    int tot=0;
    while(1){
        int n=read(),m=read();if(!n&&!m)break;
        memset(pre,0,sizeof(pre));memset(f,-127,sizeof(f));f[0][400]=0;//初始化
        for(int i=1;i<=n;i++)a[i]=read(),b[i]=read();
        for(int i=1;i<=n;i++)
            for(int j=m;j>=1;j--)//背包问题:倒序循环
                for(int k=0;k<=800;k++){
                    if(k-(a[i]-b[i])<0||k-(a[i]-b[i])>800)continue;
                    if(f[j][k]<f[j-1][k-(a[i]-b[i])]+a[i]+b[i]){
                        f[j][k]=f[j-1][k-(a[i]-b[i])]+a[i]+b[i];
                        pre[i][j][k]=1;
                    }
                }
        int cnt,ans1,ans2;
        for(int i=400;i<=800;i++)
            if(f[m][i]>=0||f[m][800-i]>=0){
                if(f[m][i]>f[m][800-i])cnt=i;
                else cnt=800-i;
                break;
            }
//因为要保证i(800-i)尽量小,所以找到了合法的就可以退出循环
        ans1=(f[m][cnt]+cnt-400)>>1;ans2=f[m][cnt]-ans1;
//ai+bi=f[m][cnt],ai-bi=cnt-400,故ans1=ai,ans2=bi
        printf("Jury #%d\nBest jury has value %d for prosecution and value %d for defence:\n",++tot,ans1,ans2);
        print(n,m,cnt);puts("");puts("");
    }
    return 0;
}

Jury Compromise

标签:初始   mes   promise   价值   分析   --   循环   ace   span   

原文地址:https://www.cnblogs.com/PPXppx/p/10990594.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!