zoukankan      html  css  js  c++  java
  • POJ1015 Jury Compromise

    POJ1015 Jury Compromise

    • 我们可以将每个候选人的辩控差作为该物品的体积之一,把辩控和作为物品的价值。
    • 因为评价差的总分值最大可能就只有[-400,400],所以我们整体加上20*m

        为叙述问题方便,现将任一选择方案中,辩方总分和控方总分
    之差简称为“辩控差”,辩方总分和控方总分之和称为“辩控和”。
    第i 个候选人的辩方总分和控方总分之差记为V(i),辩方总分和控
    方总分之和记为S(i)。现用f(j, k)表示,取j 个候选人,使其辩
    控差为k 的所有方案中,辩控和最大的那个方案(该方案称为“方
    案f(j, k)”)的辩控和。并且,我们还规定,如果没法选j 个人,
    使其辩控差为k,那么f(j, k)的值就为-1,也称方案f(j, k)不可行。
    本题是要求选出m 个人,那么,如果对k 的所有可能的取值,求
    出了所有的f(m, k) (-20×m≤ k ≤ 20×m),那么陪审团方案
    自然就很容易找到了。
    问题的关键是建立递推关系。需要从哪些已知条件出发,
    才能求出f(j, k)呢?显然,方案f(j, k)是由某个可行的方案f(j-1, x)
    ( -20×m ≤ x ≤ 20×m)演化而来的。可行方案f(j-1, x)能演化成
    方案f(j, k)的必要条件是:存在某个候选人i,i 在方案f(j-1, x)中
    没有被选上,且x+V(i) = k。在所有满足该必要条件的f(j-1, x)中,
    选出 f(j-1, x) + S(i) 的值最大的那个,那么方案f(j-1, x)再加上候选人i,
    就演变成了方案 f(j, k)。这中间需要将一个方案都选了哪些人都记录下来。
    不妨将方案f(j, k)中最后选的那个候选人的编号,记在二维数组的
    元素path[j][k]中。那么方案f(j, k)的倒数第二个人选的编号,
    就是path[j-1][k-V[path[j][k]]。假定最后算出了解方案的辩控差是k,
    那么从path[m][k]出发,就能顺藤摸瓜一步步求出所有被选中的候选人。
    初始条件,只能确定f(0, 0) = 0。由此出发,一步步自底向上递推,
    就能求出所有的可行方案f(m, k)( -20×m ≤ k ≤ 20×m)。实际解题
    的时候,会用一个二维数组f 来存放f(j, k)的值。而且,由于题目中辩
    控差的值k 可以为负数,而程序中数租下标不能为负数,所以,在程序中
    不妨将辩控差的值都加上400,以免下标为负数导致出错,即题目描述中,
    如果辩控差为0,则在程序中辩控差为400。
    大佬题解


    代码:
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    int n,m;
    int a[330],b[300];
    int f[300][1000];
    int pat[300][1000];
    int zer,t1,t2;
    int icase;
    int ans[300];
    int i,j,k;
    
    int main()
    {
        while(scanf("%d%d",&n,&m))
        {
            icase++;
            if(n==0&&m==0)  break;
            int x,y;
            memset(f,-1,sizeof(f));
            memset(pat,0,sizeof(pat));
            for(i=1 ; i<=n ; i++)
            {
                scanf("%d%d",&x,&y);
                a[i]=x-y;
                b[i]=x+y;
            }    
            
            zer=20*m;//题目中的辩控差为0,对应于程序中的辩控差为m*20
            f[0][zer]=0;
            //f[j][k]表示选j个人使其辩控差为k时的最大辩控和 
            for(j=0 ; j<m ; j++)//每次循环选出1个人
            {
                for(k=0 ; k<=zer*2 ; k++)//枚举辩控差 
                    if(f[j][k]>=0)
                    {
                        for(i=1 ; i<=n ; i++)
                            if(f[j][k]+b[i]>f[j+1][k+a[i]])
                            {
                                t1=j;t2=k;
                                while(t1>0&&pat[t1][t2]!=i)//验证i是否在前面出现过 
                                {
                                    t2-=a[pat[t1][t2]];
                                    t1--;
                                }
                                if(t1==0)
                                {
                                    f[j+1][k+a[i]]=f[j][k]+b[i];
                                    pat[j+1][k+a[i]]=i;
                                }
                            }
                    }
            }
            i=zer,j=0;
            while(f[m][i+j]<0&&f[m][i-j]<0) j++;
            if(f[m][i+j]>f[m][i-j]) k=i+j;
            else k=i-j;
            int ans1=(f[m][k]+k-zer)/2;//(和+差)/2 
            int ans2=(f[m][k]-(k-zer))/2;//(和-差)/2 
            printf("Jury #%d
    ",icase);
            printf("Best jury has value %d for prosecution and value %d for defence:
    ",ans1,ans2);
            for(i=1 ; i<=m ; i++)
            {
                ans[i]=pat[m-i+1][k];
                k-=a[ans[i]];
            }
            sort(ans+1,ans+m+1);
            for(i=1 ; i<=m ; i++) printf(" %d",ans[i]);
            printf("
    
    ");
        }
        return 0;    
    }
    View Code




  • 相关阅读:
    mybatis date类型比较
    搭建 c 语言环境 1_centos6 minimal 配置 c/c++ 编译环境
    2_eclipse配置c/c++环境
    1_eclipse导入hibernate 的DTD 文件
    1_eclipse配置c/c++开发环境
    2_修改Eclipse里面的快捷键
    1_修改注释内容
    8_对象创建、static 关键字、静态变量和成员变量的区别、文档
    7_匿名对象、封装(private)、this 关键字、构造方法
    6_面向对象基础、成员变量和局部变量的区别
  • 原文地址:https://www.cnblogs.com/wmq12138/p/10367194.html
Copyright © 2011-2022 走看看