ZOJ - 3715 枚举+贪心

题目链接
题目大意:为了成功当上老大, 1号需要用糖果收买人心,使原来投其他选手的人改投自己,直到自己的得票数比其他任何人都多
解析 自己拿到这道题是本以为是个简单的模拟,要使花费最少,只有两种情况
1、收买花费较少的人使其投自己,升序排个序,使每步花费最少
2、收买投自己直接竞争对手,能使收买次数最少
可惜多次出现段错误,心态爆炸
正解 看了其他人的代码,用的是枚举+贪心,秒在枚举自己能获胜的所有得票数,这是我没有想到的

# include <iostream>
# include <cstdio>
# include <algorithm>
# include <vector>
# include <cstring>
using namespace std;
# define MAXN 110
# define MAX 0x3f3f3f3f
int vote[MAXN], cost[MAXN], vis[MAXN], n;
vector<int>V[MAXN], Q;
int doit(int x)///以票数x获胜
{
    int ans=0;///记录要收买花费的糖果数
    int num=vis[1];///记录A要获胜的得票数
    for(int i=2; i<=n; i++)
        if(vis[i]>=x)
        {
            for(int j=0; j<=vis[i]-x; j++)ans+=V[i][j]; ///要使其票数比自己低一个
            num+=vis[i]-x+1;
        }
    if(num>x)return MAX;
    if(num==x)
    {
        for(int i=2; i<=n; i++)if(vis[i]<=x-2)return ans; ///因为自己要投一票,所以必须有一个人票数小于x-2
        int temp=MAX;
        for(int i=2; i<=n; i++)temp=min(temp,V[i][vis[i]-x+1]); ///如果没有则消掉一个人一票,排好序了
        return ans+=temp;
    }
    ///如果num<x,必须满足票数达到x
    for(int i=2; i<=n; i++)
        if(vis[i]>=x)
            for(int j=vis[i]-x+1; j<(int)V[i].size(); j++)///从0到vis[i]-x个已经加过了
                Q.push_back(V[i][j]);
        else
            for(int j=0; j<(int)V[i].size(); j++)///不小于从0开始,不影响结果
                Q.push_back(V[i][j]);
    sort(Q.begin(),Q.end());
    for(int i=0; i<x-num; i++)ans+=Q[i];
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        for(int i=0; i<MAXN; i++)V[i].clear();
        memset(vis,0,sizeof(vis));
        cin>>n;
        for(int i=2; i<=n; i++)
            cin>>vote[i], vis[vote[i]]++;
        for(int i=2; i<=n; i++)
            cin>>cost[i], V[vote[i]].push_back(cost[i]);///让某个人票数减一所要付出的代价
        for(int i=2; i<=n; i++)
            sort(V[i].begin(),V[i].end());///从小到大排序
        int ret=MAX;
        for(int x=max(1,vis[1]); x<=n-1; x++) ///枚举获胜的所有可能得票数
        {
            Q.clear();
            ret=min(ret,doit(x));
        }
        cout<<ret<<endl;
    }
    return 0;
}
///by zjz
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值