党(雾) 神奇的模拟赛 贪心

4 篇文章 0 订阅

问题描述

你现在希望组建一支足球队,一支足球队一般来说由11人组成。这11人有四种不同的职业:守门员、后卫、中锋、前锋组成。你在组队的时候必须满足以下规则:

1.足球队恰好由11人组成。
2.11人中恰好有一名守门员,3-5 名后卫,2-5 名中锋,1-3 名前锋。
3.你需要从这11人中选出一名队长。
4.你这个足球队的价值是11人的价值之和再加上队长的价值,也就是说队长的价值会被计算两次。
5.你这个足球队的花费是11人的花费之和,你的花费之和不能超过给定的上限。
现在告诉你球员的总数,每个球员的职业、价值、花费,以及花费的上限,你希望在满足要求的情况下,达到以下目标:

1.最大化队伍的价值。
2.在最大化队伍的价值的情况下,最小化队伍的花费。
你的任务是输出这三个值:价值、花费、方案数。

输入格式

第一行一个正整数N,代表可选的球员个数。
接下来N行,每行描述一个球员的信息。每行开始是一个字符串,可能的字符串有 Goalkeeper、Defender、Midfielder、Forward,分别代表该球员的职业是守门员、后卫、中锋、前锋。接下来两个数V,C,分别代表该球员的价值和花费。
最后一行一个整数,代表花费的上限。
数据保证一定存在一种解。

输出格式

一行三个整数,分表代表最大价值、最小花费和方案数。如果方案数超过了10^9,则直接输出10^9。

分析

其实题目描述和数据不符。对于100%的数据,费用上限都不必考虑。所以我们可以用贪心写。(数据水~~)

首先,可以枚举阵容的所有可能人数分配,对于每种位置,注定要选择价值最大,花费最小的前几个人。所以对于不同种类的球员,分别按照价值降序,花费升序排序后直接取前若干人即可。然后问题只剩下了种类。不难发现,某一阵容要做等价替换,只可能替换当前阵容中价值最小,花费最大的人。记与价值最小,花费最大的人相同的人共有n人,其中需要选择m人,则该阵容的方案总数为:

C(n,m)

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>

using namespace std;

struct arr{
    int val,coat;
}g[501],d[501],m[501],f[501];

int gn=0,dn=0,mn=0,fn=0;
int n;
long long val,coat,num;

inline bool cmp(arr x,arr y)
{
    if (x.val>y.val) return 1;
    if (x.val<y.val) return 0;
    if (x.coat<y.coat) return 1;
    return 0;
}

long long C(int n,int m)
{
    long long ans=1;
    for(int i=n;i>=n-m+1;i--)
        ans*=i;
    for(int i=m;i>0;i--)
        ans/=i;
    return ans;
}

int count(arr G[501],int stp,int endp)
{
    int bef=0,aft=0;
    for (int i=stp;i>0;i--)
        if ((G[i].val==G[stp].val)&&(G[i].coat==G[stp].coat))
            bef++;
        else break;
    for (int i=stp;i<=endp;i++)
        if ((G[i].val==G[stp].val)&&(G[i].coat==G[stp].coat))
            aft++;
        else break;
    return C(bef+aft-1,bef);
}

void mmm(int gm,int dm,int mm,int fm)
{
    int maxg=0,maxd=0,maxm=0,maxf=0;
    int ming=0,mind=0,minm=0,minf=0;
    for (int i=1;i<=gm;i++)
    {
        maxg+=g[i].val;
        ming+=g[i].coat;
    }
    for (int i=1;i<=dm;i++)
    {
        maxd+=d[i].val;
        mind+=d[i].coat;
    }
    for (int i=1;i<=mm;i++)
    {
        maxm+=m[i].val;
        minm+=m[i].coat;
    }
    for (int i=1;i<=fm;i++)
    {
        maxf+=f[i].val;
        minf+=f[i].coat;
    }
    int tot1=maxg+maxd+maxm+maxf;
    int tot2=ming+mind+minm+minf;
    tot1+=max(g[1].val,max(d[1].val,max(m[1].val,f[1].val)));
    int count1=count(g,gm,gn)*count(d,dm,dn)*count(m,mm,mn)*count(f,fm,fn);
    if ((val<tot1)||((val==tot1)&&(coat>tot2)))
    {
        val=tot1;
        coat=tot2;
        num=count1;
    }
    else
        if((val==tot1)&&(coat==tot2))
        {
            num+=count(g,gm,gn)*count(d,dm,dn)*count(m,mm,mn)*count(f,fm,fn);
        }
}

int main()
{
    freopen("wosa.in","r",stdin);
    freopen("wosa.out","w",stdout);
    scanf("%d",&n);
    string str;
    for(int i=1;i<=n;i++)
    {
        int a,b;
        cin>>str>>a>>b;
        if(str=="Goalkeeper")
            g[++gn]=(arr){a,b};
        if(str=="Defender")
            d[++dn]=(arr){a,b};
        if(str=="Midfielder")
            m[++mn]=(arr){a,b};
        if(str=="Forward")
            f[++fn]=(arr){a,b};
    }
    sort(g+1,g+gn+1,cmp);
    sort(d+1,d+dn+1,cmp);
    sort(m+1,m+mn+1,cmp);
    sort(f+1,f+fn+1,cmp);
    coat=100000000;
    for (int i=3;i<=min(dn,5);i++)
        for (int j=2;j<=min(5,mn);j++)
            for (int k=1;k<=min(3,fn);k++)
                if (i+j+k==10)
                    mmm(1,i,j,k);
    cout<<val<<" "<<coat<<" "<<min(num,1000000000ll);
    return 0;
    fclose(stdin);
    fclose(stdout);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值