• POJ 1015 Jury Compromise


    K - Jury Compromise
    Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

    Description

    In Frobnia, a far-away country, the verdicts in court trials are determined by a jury consisting of members of the general public. Every time a trial is set to begin, a jury has to be selected, which is done as follows. First, several people are drawn randomly from the public. For each person in this pool, defence and prosecution assign a grade from 0 to 20 indicating their preference for this person. 0 means total dislike, 20 on the other hand means that this person is considered ideally suited for the jury. 
    Based on the grades of the two parties, the judge selects the jury. In order to ensure a fair trial, the tendencies of the jury to favour either defence or prosecution should be as balanced as possible. The jury therefore has to be chosen in a way that is satisfactory to both parties. 
    We will now make this more precise: given a pool of n potential jurors and two values di (the defence's value) and pi (the prosecution's value) for each potential juror i, you are to select a jury of m persons. If J is a subset of {1,..., n} with m elements, then D(J ) = sum(dk) k belong to J 
    and P(J) = sum(pk) k belong to J are the total values of this jury for defence and prosecution. 
    For an optimal jury J , the value |D(J) - P(J)| must be minimal. If there are several jurys with minimal |D(J) - P(J)|, one which maximizes D(J) + P(J) should be selected since the jury should be as ideal as possible for both parties. 
    You are to write a program that implements this jury selection process and chooses an optimal jury given a set of candidates.

    Input

    The input file contains several jury selection rounds. Each round starts with a line containing two integers n and m. n is the number of candidates and m the number of jury members. 
    These values will satisfy 1<=n<=200, 1<=m<=20 and of course m<=n. The following n lines contain the two integers pi and di for i = 1,...,n. A blank line separates each round from the next. 
    The file ends with a round that has n = m = 0.

    Output

    For each round output a line containing the number of the jury selection round ('Jury #1', 'Jury #2', etc.). 
    On the next line print the values D(J ) and P (J ) of your jury as shown below and on another line print the numbers of the m chosen candidates in ascending order. Output a blank before each individual candidate number. 
    Output an empty line after each test case.

    Sample Input

    4 2 
    1 2 
    2 3 
    4 1 
    6 2 
    0 0 

    Sample Output

    Jury #1 
    Best jury has value 6 for prosecution and value 4 for defence: 
     2 3 

    Hint

    If your solution is based on an inefficient algorithm, it may not execute in the allotted time.

    这个题目有点难,确实不会做,看了看大牛kuangbin的代码,才大概知道怎么去写。

    意思就是给定很多组人的两组数据,求得这些人中指定个数的人,并保证这几个人的两组数据差值最小且如果差值相同的情况下和值最大。

    从kuangbin那里学到,因为这里的差值有正有负,为了使用dp,需要将整个距离向正方向位移m×20个单位,这样就可以以m×20为基点开始动态规划

    我们需要构造一个二维的dp数组dp[i][j],其中i表示的是选取几个人,j表示的是两组数据的差值。dp[i][j]表示的是两组数据的和值。

    如果等于-1的话说明选取i个人使得差值等于j这个状态不存在。


    另外开path数组代表路径,具体看代码:

    /*************************************************************************
    	> File Name: Jury_Compromise.cpp
    	> Author: Zhanghaoran
    	> Mail: chilumanxi@xiyoulinux.org
    	> Created Time: Sat 24 Oct 2015 09:26:56 PM CST
     ************************************************************************/
    
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    
    using namespace std;
    
    int dp[21][8010];
    int path[21][8010];
    int n , m;
    int p[210];
    int d[210];
    int name[21];
    bool vis[210];
    void getpath(int i, int j){
        memset(vis, 0, sizeof(vis));
        while(path[i][j] != -1){
            int k = path[i][j];
            vis[k] = true;
            i --;
            j -= p[k] - d[k];<span style="white-space:pre">		</span>//找到这一条路上的上一个结点
        }
    }
    
    void work(int i, int j, int k){
        int a = p[k] + d[k];
        int b = p[k] - d[k];
        if(dp[i + 1][j + b] == -1 || dp[i + 1][j + b] < dp[i][j] + a){
            dp[i + 1][j + b] = dp[i][j] + a;
            path[i + 1][j + b] = k;<span style="white-space:pre">		</span>//在满足转移方程的条件下更新路径
            return;
        }
    }
    
    int main(void){
        int c = 0;
        while(scanf("%d%d", &n, &m), n | m){
            c ++;
            printf("Jury #%d
    ", c);
            for(int i = 0; i < n; i ++){
                scanf("%d%d", &p[i], &d[i]);
            }
    
            int w = m * 20;
            memset(dp, -1, sizeof(dp));
            memset(path, -1, sizeof(path));
            dp[0][w] = 0;<span style="white-space:pre">					</span>//当差值为0的时候且选取人数为0的时候的总和也是0
            for(int i = 0; i < m; i ++){
                for(int j = 0; j <= 2 * w; j ++){
                    if(dp[i][j] != -1){<span style="white-space:pre">			</span>//如果dp[i][j]这个是可行的,那么遍历从i,j往上的路径
                        getpath(i, j);
                        for(int k = 0; k < n; k ++){
                            if(!vis[k])
                                work(i, j, k);
                        }
                    }
                }
            }
    
            int d1 = -1, d2 = -1, dd;
    
            for(int i = 0; i <= w; i ++){<span style="white-space:pre">		</span>//这里是往基点两边寻找差值的最小的绝对值
                if(dp[m][w + i] != -1)
                {
                    d1 = i;
                    break;
                }
            }
    
            for(int i = 0; i <=w; i ++){
                if(dp[m][w - i] != -1){
                    d2 = i;
                    break;
                }
            }
    
            if(d1 == -1 || (d2 < d1 && d2 != -1))<span style="white-space:pre">	</span>//如果只在差值为负的时候找到了
                dd = w - d2;
            else if(d2 == -1 || (d1 < d2 && d1 != -1))//如果只在差值为正的时候找到了
                dd = w + d1;
            else if(dp[m][w + d1] > dp[m][w - d2])两边都有,找到最大值
                dd = w + d1;
            else 
                dd = w - d2;<span style="white-space:pre">		</span>//得到的dd就是差值的大小基于基点
    
            int a = dp[m][dd];<span style="white-space:pre">		</span>//a为数据和
            int b = dd - w;<span style="white-space:pre">			</span>//b为实际的数据差
            int ansp = (a + b) / 2;<span style="white-space:pre">	</span>//根据和差关系计算两组数据的总和
            int ansd = (a - b) / 2;
            printf("Best jury has value %d for prosecution and value %d for defence:
    ", ansp, ansd);
            int top = 0;<span style="white-space:pre">	</span>//根据路径寻找到具体的人。
            a = m;
            b = dd;
            while(path[a][b] != -1){
                int k = path[a][b];
                name[top ++] =k;
                a --;
                b -= p[k] - d[k];
            }
            sort(name, name + top);
            for(int i = 0; i < top; i ++)
                printf(" %d", name[i] + 1);
            printf("
    
    ");
        }
    }


  • 相关阅读:
    html5 桌面提醒:Notifycations
    windows 下 apache 的虚拟主机配置
    javascript 跨域
    javascript 类型数组读取二进制数据
    javascript parseInt() 函数的进制转换陷阱
    javascript 中几个与正则表达式相关的应用
    javascript 中的二进制运算
    一段小代码,发布网页时为js 、css 文件加上版本号
    base64 编码及解码
    PHP 的比较运算与逻辑运算
  • 原文地址:https://www.cnblogs.com/chilumanxi/p/5136071.html
Copyright © 2020-2023  润新知