/*
* poj 1015 经典二维费用满背包问题 by baiwenlei
*
* 题目大意: 从n个人中选出m个作为陪审团成员。选举规则: 控方和辩方分别对n个人打分(0~20), 选出m个人
* 使得m个人的控方得分总和PJ与辩方得分总和DJ之差的绝对值|PJ-DJ|最小, 在多套方案差值相同
* 的情况下选|DJ+PJ|最大的一组。
*
* 输入: 1<=n<=200, 1<=m<=20
*
* 解题思路: 因为得分范围有限,故而可以采用枚举法将所有DJ-PJ的可能值枚举出来。
*
* 0. 对于每个人来说只有2种选择: 选或者不选 -- 搜索的思想
*
* 1. |PJ-DJ|差值没有最优子结构,但是|PJ+DJ|是有最优子结构的
*
* 2. n个人中选择m个最优方案组合,一看就是01背包中的一维费用
3.填满型背包,初始化时需初始成负数,并判断是否为负数 -- 表示非法值
*
*
*/
#include <iostream>
namespace {
using namespace std;
const int M_MAX = 20;
const int N_MAX = 200;
int d[N_MAX+1], p[N_MAX+1], diff[N_MAX+1], sum[N_MAX+1];
const int PREFER_VAL_MIN = 0;
const int PREFER_VAL_MAX = 20;
const int DP_DIFF_MIN = PREFER_VAL_MIN - PREFER_VAL_MAX;
const int DP_DIFF_MAX = PREFER_VAL_MAX - PREFER_VAL_MIN;
const int DIFF_ADJUST = DP_DIFF_MAX * M_MAX;
int f[N_MAX+1][M_MAX+1][(DP_DIFF_MAX-DP_DIFF_MIN)*M_MAX + 1];
bool path[N_MAX+1][M_MAX+1][(DP_DIFF_MAX-DP_DIFF_MIN)*M_MAX + 1];
int n, m;
void reset()
{
int s = m * DP_DIFF_MIN;
int e = m * DP_DIFF_MAX;
for (int j=0; j<=m; j++)
{
for (int d=s; d<=e; d++)
{
f[0][j][d+DIFF_ADJUST] = -1;
path[0][j][d+DIFF_ADJUST] = false;
}
}
f[0][0][DIFF_ADJUST] = 0;
}
int jury_compromise()
{
reset();
int s = m * DP_DIFF_MIN;
int e = m * DP_DIFF_MAX;
for (int i=1; i<=n; i++)
{
for (int j=0; j<=m; j++)
{
for (int d=s; d<=e; d++)
{
int k = d+DIFF_ADJUST;
f[i][j][k] = f[i-1][j][k];
path[i][j][k] = false;
if (j==0 || k-diff[i]<0 || k-diff[i]>800) continue;
if (f[i-1][j-1][k-diff[i]] == -1) continue;
if (f[i-1][j-1][k-diff[i]] + sum[i] > f[i-1][j][k])
{
f[i][j][k] = f[i-1][j-1][k-diff[i]] + sum[i];
path[i][j][k] = true;
}
}
}
}
}
void path_print(int deepth, int i, int j, int k)
{
if (deepth == m)
{
return;
}
if (path[i][j][k])
{
path_print(deepth+1, i-1, j-1, k-diff[i]);
cout << " " << i;
}
else
{
path_print(deepth, i-1, j, k);
}
return;
}
void compromise_print(int nth)
{
int sum_max = -1;
int diff_min = 0;
for (int k=0; k<=m*DP_DIFF_MAX; k++)
{
if (f[n][m][DIFF_ADJUST+k] > sum_max)
{
sum_max = f[n][m][DIFF_ADJUST+k];
diff_min = k;
}
if (f[n][m][DIFF_ADJUST-k] > sum_max)
{
sum_max = f[n][m][DIFF_ADJUST-k];
diff_min = -k;
}
if (sum_max != -1)
{
break;
}
}
int sum_d, sum_p;
sum_d = (sum_max + diff_min)/2;
sum_p = (sum_max - diff_min)/2;
cout << "Jury #" << nth << endl;
cout << "Best jury has value " << sum_p << " for prosecution"
<< " and value " << sum_d << " for defence:" << endl;
path_print(0, n, m, DIFF_ADJUST+diff_min);
cout << endl;
return;
}
}
int main()
{
int nth = 1;
while (cin>>n>>m && (n!=0 && m!=0))
{
for (int i=1; i<=n; i++)
{
cin >> p[i] >> d[i];
diff[i] = d[i] - p[i];
sum[i] = d[i] + p[i];
}
jury_compromise();
compromise_print(nth++);
}
return 0;
}
poj 1015 陪审团问题
最新推荐文章于 2018-07-25 17:30:27 发布