题意:

有n个小朋友竞选班长,1想当班长,每个人都必须选择一个人当班长,并且不可以选择自己,并且每个人都有一个权值ai,这个权值就是如果1想让这个人改变主意选择自己当班长就得给他ai个糖果,只有当1的票数是唯一最多的时候,1才能竞选班长,问1竞选班长的最小花费糖果数。(n<=100)

思路:

想了直接贪心但是似乎没有完美的方案,都会有反例。

考虑n<=100比较小,可以枚举+贪心。我第一次想的是枚举除1以外的人票数为i,如果其他人中有票数大于i的话,就贿赂投这个人的人,然后最后看1有多少票数,再根据会不会出现x,x-1,x-1…的情况分类讨论,就很麻烦,结果不对。对拍了一下发现这种做法本身就是错的,比如这一组例子,

8

3 4 3 2 4 2 7

35 13 19 2 70 98 7

其实只要13+2+7就可以竞选成功,但是如果用这种方法的话就大得多了。

正解的枚举是枚举1竞选成功的票数i,如果其他人中有票数大于i-1的话,就贿赂投这个人的人,最后如果1的票数大于i的话,不更新答案,等于i的话,更新答案,小于i的话,从还没贿赂的人里选最便宜的贿赂。但是1不是还要投一票吗?出现x,x-1,x-1…的情况那怎么办呢?其实这种情况是不可能出现的,因为x肯定大于2,总票数为x+(n-1)×(x-1)+1,2+(n-1)×1=n+2,但是总票数应该为n,相矛盾了,所以这种情况是不会出现的。

代码:

int f[110],c[110],num[110];
multiset<int>s[110];
multiset<int>ss;
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        memset(num,0,sizeof(num));
        for(int i=2;i<=n;i++)
        {
            scanf("%d",&f[i]);
            num[f[i]]++;
            s[i].clear();
        }
        for(int i=2;i<=n;i++)
        {
            scanf("%d",&c[i]);
            if(f[i]!=1)s[f[i]].insert(c[i]);
        }
        int ans=INF;
        for(int i=1;i<=n;i++)//1竞选时候的票数
        {
            ss.clear();
            int temp=0;
            int sum=num[1];//当前1的票数
            for(int j=2;j<=n;j++)
            {
                if(num[j]>i-1)
                {
                    multiset<int>::iterator it;
                    int need=num[j]-i+1;
                    for(it=s[j].begin();it!=s[j].end();it++)
                    {
                        if(need!=0){temp+=*it;need--;}
                        else ss.insert(*it);
                    }
                    sum+=num[j]-i+1;
                }
                else
                {
                    if(!s[j].empty())
                    {
                        multiset<int>::iterator it;
                        for(it=s[j].begin();it!=s[j].end();it++)ss.insert(*it);
                    }
                }
            }
            if(sum>i)continue;
            else if(sum==i)ans=min(ans,temp);
            else
            {
                int need=i-sum;
                multiset<int>::iterator it;
                for(it=ss.begin();it!=ss.end()&&need!=0;it++)
                {
                    temp+=*it;
                    need--;
                }
                ans=min(ans,temp);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

bitset用法 Previous
HDU5895 矩阵快速幂+欧拉降幂公式 Next