zoukankan      html  css  js  c++  java
  • Jury Compromise

    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
    Best jury has value %d for prosecution and value %d for defence:
    ",++tot,ans1,ans2);
    		print(n,m,cnt);puts("");puts("");
        }
        return 0;
    }
    
    
  • 相关阅读:
    Linux和Docker常用命令
    学习docker on windows (1): 为什么要使用docker
    使用xUnit为.net core程序进行单元测试(4)
    使用xUnit为.net core程序进行单元测试(3)
    高效地使用搜索引擎
    充分条件和必要条件
    上海全球“编程一小时”活动记
    C#.NET股票历史数据采集,【附18年历史数据和源代码】
    R学习笔记 ---- 系列文章
    平方根的原理
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10990594.html
Copyright © 2011-2022 走看看