http://acm.sdut.edu.cn:8080/vjudge/contest/view.action?cid=88#problem/F
题意: 在幼儿园里..每个小朋友投一票选举领导,得票最多的小朋友成为领导(若有多个..则多个领导)。现在有个小朋友相当唯一的领导,即他得到的票数是最多的,没有之一,于是准备贿赂一些小朋友。有n个小朋友,他的编号是1,现在给出编号是2~n的小朋友要投票的对象(即对应的编号),以及它贿赂2~n小朋友需要的糖果。问他能当上班上需要贿赂的最少糖果数。
思路:由于N比较小。数组num[i]表示每个小朋友的得票数。可以对第一个小朋友的得票数 t 进行枚举,范围 num[1] <= t <=n,
对于其余小朋友,若他的得票数num[i] >= t,那么应该从他那拿出 num[i]-(t-1)票给这个小朋友。这是拉票时有个规则,应该拿出需要糖果数较小的票(可以拿个辅助数组,排序一下)。若最后计算出这个小朋友得票数大于之前的枚举值t,说明t值较小,继续下次枚举。否则,再从未投第一个小朋友的人中依次选出较小的知道他的票数满足t.
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn = 110;
const int INF = 0x3f3f3f3f;
int vote[maxn],num[maxn];
int cost[maxn];
bool vis[maxn];
int tmp[maxn];
int n;
int cmp(int a, int b)
{
return cost[a] < cost[b];
}
int main()
{
int test;
int res;
scanf("%d",&test);
while(test--)
{
memset(num,0,sizeof(num));
res = INF;
scanf("%d",&n);
for(int i = 2; i <= n; i++)
{
scanf("%d",&vote[i]);
num[ vote[i] ]++;
}
for(int i = 2; i <= n; i++)
scanf("%d",&cost[i]);
for(int t = max(num[1],1); t <= n; t++)
{
int h = num[1];
int ans = 0;
memset(vis,false,sizeof(vis));
for(int i = 2; i <= n; i++)
{
if(num[i] >= t)
{
h += num[i]-(t-1);
int cnt = 0;
for(int j = 2; j <= n; j++)
if(vote[j] == i) tmp[++cnt] = j;
sort(tmp+1,tmp+1+cnt,cmp);
for(int j = 1; j <= num[i]-t+1; j++)
{
ans += cost[ tmp[j] ];
vis[ tmp[j] ] = true;
}
}
}
if(h > t) continue;
int cnt = 0;
for(int i = 2; i <= n; i++)
{
if(!vis[i] && vote[i] != 1)
tmp[++cnt] = i;
}
sort(tmp+1, tmp+1+cnt,cmp);
for(int i = 1; i <= t-h; i++)
ans += cost[ tmp[i] ];
res = min(res,ans);
}
printf("%d\n",res);
}
return 0;
}