您的位置:首页 > 其它

POJ 1015--Jury Compromise

2017-07-06 23:21 387 查看

题意

题目大意是讲,在遥远的国家佛罗布尼亚,嫌犯由陪审团决定是否有罪。先随机挑选n个人作为陪审团的候选人,然后再从这n个人中选m人组成陪审团。控方和辩方会给所有候选人打分,分值从0到20(分数越高代表越喜欢)。为了公平起见,选出的m个人必须满足辩方总分和控方总分之差的绝对值最小。如果出现多种方案,那么选辩控双方总分之和最大的方案即可。

分析

比较容易想到的就是动态规划,先对候选人进行排序,由于评分差为-20到20,将评分差加上20,变为0到40。用一个二维数组表示选中的第几号人v[index][value], 假定评分数组为diff[] = {10, 20, 23, 29…},比如v[1][20]==2,代表选第一个人时,评分为20时,选中了第2号人。以此类推v[2][43]==3,这样可以得到一个完整的选择链(想要知道前一个人的选择,只需求v[2 - 1][43 - diff[3]] = v[1][20] = 2)。

最后,假定需要选择10个人,若v[10][400] != 0,那么v[10][400]下面的选择链便是最优解。反之搜索最靠近v[10][400]的情况即可。比如当v[10][390] != 0 && v[10][405] != 0,那么v[10][405]必定优于v[10][390]。事实上,这种方法会有重复计算的情况,再加优化的话,100MS内应该没什么问题。

代码如下:

Memory: 328K Time: 250MS Length:154LINES

#include<iostream>
#include<cstring>
using namespace std;
struct JURY                           //陪审员
{
int count;                    //原始编号
int pi;
int di;
};
int v[21][801] = {};
JURY pJury[200];
inline int inline_sum(JURY& j) { return j.di + j.pi; }
inline int inline_diff(JURY& j) { return j.pi - j.di + 20; }
void Sort_Insert(const int c)          //插入排序
{
for (int i = 1; i < c; ++i)
{
JURY temp = pJury[i];
int j = i;
while (j > 0)
if (inline_diff(temp) < inline_diff(pJury[j - 1]))
{
pJury[j] = pJury[j - 1];
--j;
}
else    break;
pJury[j] = temp;
}
}
void Find_min_max(const int c, int count, int& minval, int& maxval)  //计算前后count个候选人辨控差的和
{
for (int i = 0; i < count; ++i)
{
minval += inline_diff(pJury[i]);
maxval += inline_diff(pJury[c - 1 - i]);
}
}
int Update(int depth, int value, int tmpvalue)                    //更新选择链
{
int cu = 0;
int pen = 0;
while (depth > 0)
{
cu += inline_sum(pJury[v[depth][value]]);
pen += inline_sum(pJury[v[depth][tmpvalue]]);
value -= inline_diff(pJury[v[depth][value]]);
tmpvalue -= inline_diff(pJury[v[depth][tmpvalue]]);
--depth;
}
return pen - cu;
}
bool find_pos(int depth, int value, int k)                    //在一个选择链上查找某个候选人是否已经存在
{
while (depth > 0)
{
if (v[depth][value] == k)
return true;
value -= inline_diff(pJury[v[depth][value]]);
--depth;
}
return false;
}
inline int inline_max(int a, int b) { return inline_sum(pJury[a]) > inline_sum(pJury[b]) ? a : b; }
int main()
{
int candidates = 0;
int members = 0;
int count = 0;
while (cin >> candidates >> members && candidates != 0 && members != 0)
{
int selected[200] = {};
memset(&v, -1, sizeof(v));
for (int i = 0; i < candidates; ++i)
{
cin >> pJury[i].pi >> pJury[i].di;
pJury[i].count = i;
}
Sort_Insert(candidates);
for (int j = 1; j <= members; ++j)
{
int maxval = 0;
int minval = 0;
Find_min_max(candidates, j, minval, maxval);
for (int i = minval; i <= maxval; ++i)
{
for (int k = 0; k < candidates - members + j; ++k)
{
if (i < inline_diff(pJury[k]));
else if (i == inline_diff(pJury[k]) && j == 1)          v[j][i] = v[j][i] != -1 ? inline_max(v[j][i], k) : k;
else if (v[j - 1][i - inline_diff(pJury[k])] != -1)
{
if (v[j][i] == -1) //无值时,先搜索是否已存在
{
if (!find_pos(j - 1, i - inline_diff(pJury[k]), k))     v[j][i] = k;
}
else     //有值时,先搜索,再比较
{
if (!find_pos(j - 1, i - inline_diff(pJury[k]), k))
if (inline_sum(pJury[k]) - inline_sum(pJury[v[j][i]]) + Update(j - 1, i - inline_diff(pJury[v[j][i]]), i - inline_diff(pJury[k])) > 0)
v[j][i] = k;
}
}
}
}
}
int v1, v2, val;
val = v1 = v2 = members * 20;
if (v[members][v1] == -1)              //寻找最优解
{
while (v1 <= members * 40)
{
++v1;
--v2;
if (v[members][v1] == -1 && v[members][v2] != -1)
{
val = v2;
break;
}
else if (v[members][v1] != -1 && v[members][v2] == -1)
{
val = v1;
break;
}
else if (v[members][v1] != -1 && v[members][v2] != -1)
{
if (inline_sum(pJury[v[members][v1]]) - inline_sum(pJury[v[members][v2]]) + Update(members - 1, v2 - inline_diff(pJury[v[members][v2]]), v1 - inline_diff(pJury[v[members][v1]])) > 0)
val = v1;
else            val = v2;
break;
}
}
}
int sum_pi = 0;
int sum_di = 0;
for (int i = members; i > 0; --i)
{
selected[pJury[v[i][val]].count] = 1;
sum_pi += pJury[v[i][val]].pi;
sum_di += pJury[v[i][val]].di;
val -= inline_diff(pJury[v[i][val]]);
}
cout << "Jury #" << ++count << endl;
cout << "Best jury has value " << sum_pi << " for prosecution and value " << sum_di << " for defence:" << endl;
int mm = 0;
for (int i = 0; i < candidates && mm < members; ++i)
if (selected[i])
{
cout << " " << i + 1;
++mm;
}
cout << endl << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj