搜索-hdu-3720-Arranging Your Team

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=3720

题目大意:

有23个人,告诉每个人的名字,能力值,以及踢球的位置。要求选出1个守门员,2个前锋,4个中场,4个后卫。给m个关系,该关系的两个人如果同时在场,就会得到相应的分数值va(注意va可以为负值)。求怎样安排使得在场的人总价值最大。

解题思路:

先处理出每种位置的人分布,然后枚举是哪几个人,凑成后更新总价值即可。注意va可能为负数。

代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define Maxn  30
map<string,int>nameid;
vector<int>pos[5]; //pos[i]保存位置i的人员分布
map<string,int>posid; //位置的标号
int va[Maxn],add[Maxn][Maxn],ans;
bool vis[Maxn];

int Cal()
{
    int res=0;

    for(int i=1;i<=23;i++) //已选了哪些人
        if(vis[i])
            res+=va[i];
    for(int i=1;i<=23;i++) //人之间关系的相互影响
        for(int j=i+1;j<=23;j++)
        {
            if(vis[i]&&vis[j])
            {
                res=res+add[i][j];
            }

        }
    return res;
}
void dfs4(int num,int cur)
{
    if(num==4)
    {
        ans=max(ans,Cal()); //已全部选完了
        return ;
    }
    for(int i=cur;i<pos[4].size();i++) //从下一个开始选
    {
        vis[pos[4][i]]=true;
        dfs4(num+1,i+1);
        vis[pos[4][i]]=false;
    }
}

void dfs3(int num,int cur)
{
    if(num==4)
    {
        dfs4(0,0);
        return ;
    }
    for(int i=cur;i<pos[3].size();i++)
    {
        vis[pos[3][i]]=true;
        dfs3(num+1,i+1);
        vis[pos[3][i]]=false;
    }
}

void dfs2(int num,int cur)
{
    if(num==2)
    {
        dfs3(0,0);
        return ;
    }
    for(int i=cur;i<pos[2].size();i++)
    {
        vis[pos[2][i]]=true;
        dfs2(num+1,i+1);
        vis[pos[2][i]]=false;
    }
}

void dfs1(int num,int cur)
{
    if(num==1)
    {
        dfs2(0,0);
        return ;
    }
    for(int i=cur;i<pos[1].size();i++)
    {
        vis[pos[1][i]]=true;
        dfs1(num+1,i+1);
        vis[pos[1][i]]=false;
    }
}


int main()
{
    posid["goalkeeper"]=1; //书名对应标号
    posid["striker"]=2;
    posid["midfielder"]=3;
    posid["defender"]=4;

    string name,job;
    while(cin>>name)
    {
        nameid.clear();
        for(int i=1;i<=4;i++) /
            pos[i].clear();
        memset(add,0,sizeof(add));

        nameid[name]=1;
        scanf("%d",&va[1]);
        cin>>job;
        pos[posid[job]].push_back(1); //该职业新增一人
        for(int i=2;i<=23;i++)
        {
            cin>>name>>va[i]>>job;
            nameid[name]=i; //人的标号
            pos[posid[job]].push_back(i);//先找到该位置标号,然后添加该人
        }

        int m;

        scanf("%d",&m);
        while(m--)
        {
            string name2;
            int tmp;

            cin>>name>>name2>>tmp; //人之间的关系值
            add[nameid[name]][nameid[name2]]=tmp;
            add[nameid[name2]][nameid[name]]=tmp;
        }
        if(pos[1].size()<1||pos[2].size()<2||pos[3].size()<4||pos[4].size()<4)
        {
            printf("impossible\n");
            continue;
        }

        ans=-INF;
        memset(vis,false,sizeof(vis));
        dfs1(0,0);
        printf("%d\n",ans);

    }
   return 0;
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值