POJ 1015 Jury Compromise
POJ 1015 Jury Compromise
题意:
有 \(n\) 对数字,要从 \(n\) 对数字中选出 \(m\) 对,目标是使得第一组的数字和与第二组的数字和的差的绝对值最小。基于差的绝对值最小的基础上,两组数的总和最大,输出两组最后的分数,以及选法。
思路:
类似 \(01\) 背包问题,并且需要输出方案。
因为选出 \(m\) 对,所以肯定有两个维度 \(f[i][j]\) : 遍历到第 \(i\) 个物品,选了 \(j\) 个人,然后我们目的是使得这个绝对值差最小,通过分析数据我们可以知道,两者的差最多去到 \(800\) ,所以考虑第三维度直接记录两者的差值。因为出现负数,所以这里用 \(basic = 801\) 来表示差值为 \(0\) 。
定义 \(f[i][j][k]\) 为遍历到第 \(i\) 个人,已经选了 \(j\) 个人,当前两组的差值为 \(k\) 时的总和最大值。
然后每对数字分选和不选两种情况。就是 \(01\) 背包问题。
最后,遍历一次来找出最终的答案即可。
本题的初始化,只有当选了之后才有,所以这里直接从第一组开始初始化(注意初始化 \(f[1][1][]\) 之后 \(f[2][1][]\) 也需要 \(f[1][1][]\))
这道题细节比较多,比如说每个案例输出一行,输出的选法前面有个空格(当然还是我太菜写太丑的原因)
实现:
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 205, M = 1650, INF = -1e9, base = 801;
int a[N], b[N];
int f[N][25][M];
int main()
{
int n, m;
int lun = 1;
while (scanf("%d%d", &n, &m) != EOF)
{
if (!n && !m)
break;
for (int i = 1; i <= n; i++)
scanf("%d%d", &a[i], &b[i]);
//初始化1
for (int i = 0; i < N; i++)
for (int j = 0; j < 25; j++)
for (int k = 0; k < M; k++)
f[i][j][k] = INF;
//初始化2
for (int i = 1; i <= n; i++)
f[i][1][a[i] - b[i] + base] = a[i] + b[i];
for (int i = 1; i <= n; i++)
{
//注意这里要取 min(i,m)
for (int j = 1; j <= min(i, m); j++)
{
for (int k = 0; k < M; k++)
{
//当前不选
if (f[i - 1][j][k] != INF)
f[i][j][k] = max(f[i][j][k], f[i - 1][j][k]);
//当前选
int sum = k - a[i] + b[i];
if (sum >= 0 && sum < M && f[i - 1][j - 1][sum] != INF)
{
f[i][j][k] = max(f[i][j][k], f[i - 1][j - 1][sum] + a[i] + b[i]);
}
}
}
}
int re = 0, redif = -INF, fl;
for (int i = 0; i < M; i++)
{
if (f[n][m][i] != INF)
{
if (abs(i - base) < redif)
{
redif = abs(i - base);
re = f[n][m][i];
fl = i;
}
else if (abs(i - base) == redif && f[n][m][i] >= re)
{
re = f[n][m][i];
fl = i;
}
}
}
int rex = (redif + re) / 2;
int rey = re - rex;
//上面的计算方法,求出来的rex >= rey所以还需要根据 fl 对应的正负来判断哪个对应哪个
if (fl < 801)
swap(rex, rey);
printf("Jury #%d \n", lun++);
printf("Best jury has value %d for prosecution and value %d for defence: \n", rex, re - rex);
vector<int> peo;
int j = m, k = re;
for (int i = n; i >= 1; i--)
{
if (j != 1)
{
if (fl - (a[i] - b[i]) >= 0 && fl - (a[i] - b[i]) < M && k == f[i - 1][j - 1][fl - (a[i] - b[i])] + (a[i] + b[i]))
{
peo.push_back(i);
j--;
fl -= a[i] - b[i];
k -= a[i] + b[i];
}
}
else if (j == 1)
{
if (fl - (a[i] - b[i]) >= 0 && fl - (a[i] - b[i]) < M && k == a[i] + b[i])
{
peo.push_back(i);
j--;
fl -= a[i] - b[i];
k -= a[i] + b[i];
break;
}
}
}
for (int i = peo.size() - 1; i >= 0; i--)
{
printf(" %d", peo[i]);
}
printf("\n\n");
}
return 0;
}