zoj 3715 Kindergarten Election
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5018
题意:
有n个学生要选出班长编号从1到n,1号人比较虚荣,想自己当班长,每个人都可以投一票给自己心目中的人但不能投给自己,只要谁的票数最高谁就可以当班长。给出每个人心目中的投票人,以及贿赂每个人所需要的糖果,(只要你给了那个人一定数目的糖果他就会支持你) 。问1号如果当班长的话,最少需要的糖果数。
思路:
由于这里的n比较小,我们只要枚举1当班长时的得票数x,然后再将其他人的得票数大于x的变为x-1 (减少的给1并且减少的肯定是所需糖果树最少的),然后检查最后1的得票数,如果大于x那么肯定无解,如果等于x,只要保证2到n中有得票数<= x - 2的即可。如果小于x,那么从剩下没有支持1的中,找出所需糖果树最少的来贿赂得票知道等于x为止。
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout) #define M 137 #define N 115 using namespace std; const int inf = 0x7f7f7f7f; const int mod = 1000000007; int ans,res; int vote[N],c[N],b[N]; map<int,int>mp; bool vt[N],vt2[N]; int n; int getR(int k) { for (int i = 2; i <= n; ++i) { if (b[i] >= k) { while (b[i] != k - 1) { int t1 = 0, t2 = inf; for (int j = 2; j <= n; ++j) { if (!vt2[j] && mp[j] == i && c[j] < t2) { t1 = j; t2 = c[j]; } } ans += t2; vt2[t1] = true; b[i]--; b[1]++; } } } return b[1]; } int main() { // Read(); int T,i,j; int x; scanf("%d",&T); while (T--) { scanf("%d",&n); CL(vote,0); mp.clear(); CL(vt,false); for (i = 2; i <= n; ++i) { scanf("%d",&x); mp[i] = x; vote[x]++;//x的得票数 if (x == 1) vt[i] = true;//i是否支持1 } for (i = 2; i <= n; ++i) scanf("%d",&c[i]); res = inf; for (int k = vote[1]; k <= n; ++k) { if (k <= 1) continue; for (i = 1; i <= n; ++i) b[i] = vote[i]; for (i = 1; i <= n; ++i) vt2[i] = vt[i]; ans = 0; int no = getR(k); if (no == k) { for (j = 2; j <= n; ++j)//保证存在一个得票数小于等k - 2的来结束1的票 { if (b[j] <= k - 2) break; } if (j <= n) { res = min(res,ans); } } else if (no < k) { while (no < k)//从没有支持1的人中选出所需糖果数最少的人贿赂得票 { int t1 = 0,t2 = inf; for (i = 2; i <= n; ++i) { if (!vt2[i] && c[i] < t2) { t1 = i; t2 = c[i]; } } vt2[t1] = true; ans += t2; no++; } res = min(res,ans); } } printf("%d\n",res); } return 0; }