zoukankan      html  css  js  c++  java
  • [poj1015]Jury Compromise[DP]

    题意:$n$个物品选$m$个,每个物品有两个权值$A[i]$和$B[i]$,要求选出的$m$个物品$left|sum A[i]-sum B[i] ight|$最小,当这个差值相同时,选择$sum A[i]+sum B[i]$最大的,输出$sum A[i]$,$sum B[i]$,方案。

    题解:

    令$V=left|sum A[i]-sum B[i] ight|$

    $S=sum A[i]+sum B[i]$   

    $s[i]=A[i]+B[i]$

    $v[i]=A[i]-B[i]$

    设$f[j][k]$表示选过第$j$个后 $k=sum A[i]-sum B[i]$(注意没有绝对值) 时$S$的最大值,若$f[j][k]==-1$表示不存在合法方案。

    $path[j][k]$表示$f[j][k]$是由$f[j-1][k]$选择了$path[j][k]$后得到的,即状态$f[j][k]$处最后选择的物品。

    最后方案的输出用$path$数组向前回溯,考虑$path[j][k]$的前一个选的是$path[j-1][k-v[path[j][k]]]$。

    转移如下:

    if (f[j-1][k]+s[i] > f[j][k+v[i]] && !Selected(j-1,k,i) )//i没有被之前的状态选择
    	f[j][k+v[i]]=f[j-1][k]+s[i], path[j][k+v[i]]=i;

    这样最终答案是$left| k ight|$最小的合法$f[m][k](f[m][k]!=-1)$。

    因为$f[m][k]=sum A[i]+sum B[i]$

    $k=sum A[i]-sum B[i]$

    所以答案的$sum A[i]=(f[m][k]+k)/2$

    $sum B[i]=(f[m][k]-k)/2$

    最后,方案的输出用$path$数组向前回溯,考虑$path[j][k]$的前一个选的是$path[j-1][k-v[path[j][k]]]$。

    将得到的方案排序输出即可。 为了避免负数下表,要将第二维平移,需注意细节。

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstdio>
     4 #include <cstdlib>
     5 #include <cstring>
     6 #include <ctime>
     7 #include <cmath>
     8 #include <vector>
     9 
    10 using namespace std;
    11 
    12 int    n,m,a[210],b[210],v[210],s[210],fix,Kase;
    13 int    f[1100][1100],path[1100][1100];
    14 
    15 bool    Selected(int j,int k,const int i)
    16 {
    17     while(j>0 && path[j][k]!=i)  
    18         {  k-=v[path[j][k]]; j--; }  
    19     return j; 
    20 }
    21 
    22 int main()
    23 {
    24     while (~scanf("%d%d",&n,&m) && n && m)
    25     {
    26         for (int i=1;i<=n;++i)
    27             scanf("%d%d",&a[i],&b[i]),
    28               v[i]=a[i]-b[i],s[i]=a[i]+b[i];
    29         
    30         fix=m*20; memset(f,0xff,sizeof(f)); f[0][fix]=0;
    31 
    32         for (int j=1;j<=m;++j) for (int k=0;k<=fix<<1;++k)
    33         {
    34             if (f[j-1][k]<0)continue;
    35             for (int i=1;i<=n;++i)
    36             {
    37                 if (f[j-1][k]+s[i] > f[j][k+v[i]] && 
    38                     !Selected(j-1,k,i) )
    39                 {
    40                     f[j][k+v[i]]=f[j-1][k]+s[i];
    41                     path[j][k+v[i]]=i;
    42         }    }    }
    43 
    44         int tt; for(int k=0;k<=fix;++k)
    45             if(f[m][fix-k]>=0 || f[m][fix+k]>=0) { tt=k; break; }
    46 
    47         int temp=(f[m][fix-tt]>f[m][fix+tt]?(fix-tt):(fix+tt));
    48         printf("Jury #%d
    Best jury has value %d for prosecution and"
    49             " value %d for defence: 
    ",++Kase,
    50               (f[m][temp]+temp-fix)>>1,(f[m][temp]-temp+fix)>>1);
    51 
    52         vector<int>    vec; tt=temp;
    53         for(int j=m;j;--j)
    54         { vec.push_back(path[j][tt]); tt-=v[vec.back()]; }
    55 
    56         sort(vec.begin(),vec.end());
    57         for(int i=0;i<(int)vec.size();++i) printf(" %d",vec[i]);
    58 
    59         printf("
    ");
    60     }
    61     return 0;
    62 }
  • 相关阅读:
    Haskell 编写几个递归函数 练习 typeclass 模式匹配等
    Haskell-chp01
    阉割的List
    实现简单的string类
    构造函数语义学——Copy Constructor 的构造操作
    BinarySearchTree-二叉搜索树
    对象模型
    二叉树的遍历
    带头尾结点的单链表
    Effective Modern C++ ——条款5 优先选择auto,而非显式型别声明
  • 原文地址:https://www.cnblogs.com/Gster/p/5617772.html
Copyright © 2011-2022 走看看