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