POJ-1015ジュリー妥協(DP | 01バックパック)

トピック:

Frobnia、遠くの国では、裁判所の裁判での判決は、一般大衆のメンバーで構成される陪審によって決定されます。裁判が開始するように設定されるたびに、陪審員は、次のように行われている、選択しなければなりません。まず、いくつかの人々は、公共からランダムに描かれています。このプール内の各人物について、防衛、検察はこの人のために自分の好みを示す0から20までのグレードを割り当てます。この人は、陪審員のために理想的に適し考えられていることを一方の手段で0手段総嫌い、20。
両者の成績に基づき、裁判官は陪審員を選択します。公正な裁判を確保するためには、陪審員の傾向は、いずれかの防衛を優先するか、検察はできるだけバランスする必要があります。陪審は、従って、双方に十分であるように選択されなければなりません。
私たちは今、これがより正確になります:私は、各潜在的な陪審員のための潜在的な陪審員2つの値ジ(防衛の値)とPI(検察側の値)、nのプールを与え、あなたはM人の陪審員を選択するようにしています。Jは、の部分集合である場合、{1、...、n}は、m個の要素を持つ、次にD(J)= SUM(DK)K Jに属する
とP(J)= SUM(PK)K Jに属する合計であります防衛と訴追のため、この陪審の値。
最適な審査員のためのJ、値| D(J)、 - P(J)| 最小限でなければなりません。最小を有するいくつかのジュリーズがある場合| D(J)、 - P(J)は|陪審は、両当事者のために可能な限り理想ようでなければならないので、D(J)+ P(j)を最大化する一方が選択されるべきです。
あなたはこの陪審員の選任プロセスを実装し、候補のセット与えられた最適な陪審員を選ぶプログラムを書くことです。

入力:

入力ファイルは、いくつかの陪審員の選択ラウンドが含まれています。二つの整数nとmを含む行との各ラウンドを開始します。Nは候補の数であり、審査員の数をMです。
これらの値は、N = N <= 200、1 <= M <= 20、そしてもちろん、M <= <1を満足します。iは1、...、N =は、次のn行は、二つの整数PIとジ含みます。空白行は、次の各ラウンドを分離します。
N = M = 0を有する円形のファイルが終了します。

出力:

各ラウンド出力陪審選択ラウンド(「ジュリー#1」、「審査員#2」、等)の数を含む行のため。
次の行に別の行の下と上に示したように、あなたの陪審の値D(j)及びP(J)は昇順でM選ばれた候補者の数を印刷する印刷します。出力個々の候補番号の前に空白。
各テストケースの後に出力空行。

サンプル入力:

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

サンプル出力:

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

質問の意味:

遠い国で佛罗布尼亚、容疑者が有罪である、陪審員が決定しなければなりません。陪審員は、公衆からの審査員によって選ばれました。N個の第1ランダム陪審候補として個体を選択し、次に個々の選択されたm-部材陪審Nから。検察側と弁護は、すべての候補者の得点、0-20からのスコアに、候補者の愛の程度に基づいて行われます:Mの人々があるアプローチを選択します。公平を期すためには、陪審員を選択した裁判官の原理は次のとおりです。メートル個人が選択したが、防衛および合計スコアの起訴の総得点の差の絶対値が最小を満たす必要があります。防衛の合計スコアとのさまざまなオプションの絶対値のうち起訴間で同じ差異がある場合は、コントロールの当事者のうちの防衛を選択して、最大のプログラムをすることができます。

入力の複数組、nおよびmの各入力。1 <= N <= 200,1 <= M <= 20、M <= N。次のn行は、入力候補得点防衛と検察が変更さnまでの最初から候補番号です。N = M = 0の最後のセットのデータ入力端。

分析:

ナップザック問題として01メートルは、N個のアイテムからアイテムを選択します。検察と防衛目的画分および合計アレイ、スコア、およびレコードの防衛と起訴デアレイレコードと防御と起訴の全ての画分の電流位相差との差を記録し、アレイ状態は、記録DPすることができます加えて、DP配列はまた、現在のメンバーのために選択された現在のメンバー数を記録すべきか、あなたはそれを選択した場合、我々は、それのために投票しないように選択することができ、その後、検察側と弁護の違いは、現在のメンバーの値を追加し、メンバーの数1を追加し、それをスキップそう、あなたはそれは我々がそれを選択し、現在のポイント差定数検察と弁護し、大下、両当事者を有効に選択した場合、それを選択し、それを選択するかどうかをどのように決定し、DP [I] [J] [k]はI、Jのメンバーが選択されたメンバーの現在の数を表し、最大の電流差が当事者kと点の間の差の両方の場合に双方を指し、最初の配列ためIF(DP [J-1] [K] +和[:次元空間は、スクロール・アレイ、DP [I] [J] [K] [K]を[j]をDPに変換することができ、状態遷移を表すことができるように省略することができますI]> DP [J] [K +ド[I])DP [J] [K +ド[I] = DP [J-1] [K] +和[I]。I〜Jの選出されたメンバーはその後、その後、メンバーを選択し、検察側と弁護と違い、K +デ[i]は良く取得することができます(大)ソリューションのメンバーを選択する場合はケースを表します。kが負でないとデ配列が存在し得るので、負であり、20点の最大スコアの各々、極端なケースを検討するため、m個の個々の和が解除されますされ、初期の時点から20×m個の点を定義することが可能です-20×M、20×Mと、定義DP [0] [20 * M]に= 0、初期点、他の値は、状態の前にあれば状態は、訪問されていないを表す、-1 DPすべてのセットであります状態は訪れていない、それは我々が最終的に20から拡大し始め、直接、状態遷移方程式を決定するために継続する必要はありません×2にこの点をM、、状態が到着する最初に訪れたの答えです(この時点では検察側と弁護双方の理由差が最小であり、防衛、起訴と最大の両方で両当事者間のすべての電流差)、パスベクトルアレイレコードパス定義を使用する必要性に加えて、特定のオペレーションコードを参照してください。

コード:

#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int maxn = 205;
int sum[maxn],de[maxn];
int dp[25][maxn<<2];
vector<int> path[25][maxn<<2];
int main(void){
    int n,m,p,d,cnt = 1;
    while (scanf("%d%d",&n,&m),n+m){
        for (int i = 1; i <= n; i++){
            scanf("%d%d",&p,&d);
            sum[i] = p+d;
            de[i] = p-d;
        }
        int flag = m*20;
        memset(dp,-1,sizeof dp);
        dp[0][flag] = 0;
        for (int i = 1; i <= n; i++){
            for (int j = m; j >= 1; j--){
                for (int k = 0; k <= flag*2; k++){
                    if (k+de[i] < 0 || k+de[i] > flag*2) continue;
                    if (dp[j-1][k] == -1) continue;
                    if (dp[j-1][k]+sum[i] > dp[j][k+de[i]]){
                        dp[j][k+de[i]] = dp[j-1][k] + sum[i];
                        path[j][k+de[i]] = path[j-1][k];
                        path[j][k+de[i]].push_back(i);
                    }
                }
            }
        }
        int ans = 0;
        while (dp[m][flag-ans] == -1 && dp[m][flag+ans] == -1) ans++;
        int tmp = dp[m][flag+ans]>dp[m][flag-ans]?flag+ans:flag-ans;
        printf("Jury #%d\nBest jury has value %d for prosecution and value %d for defence:\n",cnt++,(dp[m][tmp]+tmp-flag)>>1,(dp[m][tmp]-tmp+flag)>>1);
        for (int i = 0; i < m; i++){
            printf(" %d",path[m][tmp][i]);
        }
        puts("\n");
    }
    return 0;
}

蓄積と学習課する必要があります。

圧延パスパスアレイANS = 0後の記録一連の動作

参考著者:

UVA 323審査員妥協 - 01リュック変形

おすすめ

転載: www.cnblogs.com/hznudreamer/p/12375819.html