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

 

 

posted @ 2013-05-17 21:32  E_star  阅读(673)  评论(0编辑  收藏  举报