Kindergarten Election(枚举+贪心)

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;
}



你可能感兴趣的:(枚举,贪心)