1083. 【GDOI2006】拯救亚特兰蒂斯

Description

亚特兰蒂斯人激怒了众神,众神之王宙斯决定要好好教化他们。这时,一位居心叵测的 bug 魔王看准了时机,打着“教化亚特兰蒂斯人”的旗号,暗地里策划了一个极具野心的阴谋:铲平亚特兰蒂斯。善良的宙斯并没有发现他的阴谋,草率地批准了他这次“教化”行动,于是一场危机就要降临亚特兰蒂斯了……

幸好亚特兰蒂斯拥有一位相当优秀的先知 Cubic,他发现了 bug 魔王的阴谋,并了解到bug魔王会派出N种怪物来入侵亚特兰蒂斯,现在就要想办法对付这N种怪物。Cubic 还了解到,每一种怪物都对应一种剑术和一种法术,这种怪物可以被这对应的剑术打败,也可以被对应的法术打败。不同的怪物可能对应不同的剑术和法术,而一种剑术或法术可以击败多种怪物。只要 Cubic 得到某怪物的信息,他就可以知道对应的剑术和法术,不会只知其一。

亚特兰蒂斯里最优秀的剑术师是 RC,最优秀的法术师是 Aesop,这次为了保护亚特兰蒂斯,他们都愿意挺身而出。但问题是他们并不会这些特定的剑术和法术,必须抓紧时间学习。但由于学习新剑术或新法术需要闭关学习,为了避免 bug 魔王搞奇袭,必须至少留下其中一个专门看守,于是他们两个就不能同时去学习了。

现在 bug 魔王已经屯好兵了,时间所剩无几,他们必须在最短的时间内学会相应的剑术和法术,以打败所有的怪物。学习一种剑术或一种法术所需要的时间都为 1。现在问题是,他们到底应该学习哪种剑术和法术,才能在最短时间内拥有打败所有怪物的能力呢?

即便是再聪明的 Cubic 这次都头痛了。于是他找到了你——亚特兰蒂斯的顶级技术顾问,来帮他解决这个问题。所以,拯救亚特兰蒂斯的重任就交给你了。

Solution

首先先处理输入,\(\mathrm{map}\) 或者哈希都可以。

处理出每个怪物可以被哪种剑术和法术击败,如果有怪物无法被击败,那么无解。

将每个怪物的剑术和法术连边,那么题目变成求点集的最小覆盖,求最大匹配即可。

建超级源和超级汇,源点连向剑术,法术连向汇点。跑匈牙利或者网络流。

Code

#include<map>
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define mo 19260817
#define N 10005
#define inf 2147483647
using namespace std;
struct node
{
    int to,next,flow;
}a[N<<2];
map<string,int> monster;
int n,m1,m2,num,tot,S,T,ans,atk[N][3],head[N<<1],cur[N<<1],deep[N<<1];
char ch[20];
bool b[N];
void add(int x,int y)
{
    a[++tot].to=y;a[tot].flow=1;a[tot].next=head[x];head[x]=tot;
    a[++tot].to=x;a[tot].flow=0;a[tot].next=head[y];head[y]=tot;
}
bool bfs()
{
    memset(deep,0,sizeof(deep));
    queue<int> q;
    deep[S]=1;q.push(S);
    while (!q.empty())
    {
        int x=q.front();q.pop();
        for (int i=head[x];i;i=a[i].next)
        {
            int y=a[i].to;
            if (!deep[y]&&a[i].flow)
            {
                deep[y]=deep[x]+1;
                q.push(y);
                if (y==T) return true;
            }
        }
    }
    return false;
}
int dfs(int x,int flow)
{
    if (x==T) return flow;
    int res=0;
    for (int &i=cur[x];i;i=a[i].next)
    {
        int y=a[i].to;
        if (a[i].flow&&deep[y]==deep[x]+1)
        {
            int fl=dfs(y,min(flow,a[i].flow));
            if (!fl) continue;
            a[i].flow-=fl;a[i^1].flow+=fl;
            res+=fl;flow-=fl;
            if (!flow) break;
        }
    }
    return res;
}
int main()
{
    freopen("T3.in","r",stdin);
    freopen("T3.out","w",stdout);
    while (true)
    {
        scanf("%d%d%d",&n,&m1,&m2);
        if (n==-1&&m1==-1&&m2==-1) break;
        monster.clear();
        for (int i=1;i<=n;++i)
        {
            string s="";
            scanf("%s",ch);
            int len=strlen(ch);
            for (int j=0;j<len;++j)
                s+=ch[j];
            monster[s]=i;
        }
        memset(b,false,sizeof(b));
        for (int i=1;i<=m1;++i)
        {
            scanf("%s",ch);
            scanf("%d",&num);
            for (int j=1;j<=num;++j)
            {
                string s="";
                scanf("%s",ch);
                int len=strlen(ch);
                for (int k=0;k<len;++k)
                    s+=ch[k];
                atk[monster[s]][1]=i;
                b[monster[s]]=true;
            }
        }
        for (int i=1;i<=m2;++i)
        {
            scanf("%s",ch);
            scanf("%d",&num);
            for (int j=1;j<=num;++j)
            {
                string s="";
                scanf("%s",ch);
                int len=strlen(ch);
                for (int k=0;k<len;++k)
                    s+=ch[k];
                atk[monster[s]][2]=i;
                b[monster[s]]=true;
            }
        }
        bool flag=true;
        for (int i=1;i<=n;++i)
            if (!b[i])
            {
                printf("Poor Atlantis!\n");
                flag=false;
                break;
            }
        if (!flag) continue;
        tot=1;
        memset(head,0,sizeof(head));
        S=m1+m2+1;T=m1+m2+2;
        for (int i=1;i<=n;++i)
            if (atk[i][1]&&atk[i][2]) add(atk[i][1],atk[i][2]+m1);
        for (int i=1;i<=m1;++i)
            add(S,i);
        for (int i=1;i<=m2;++i)
            add(i+m1,T);
        ans=0;
        while (bfs())
        {
            for (int i=1;i<=m1+m2+2;++i)
                cur[i]=head[i];
            ans+=dfs(S,inf);
        }
        printf("%d\n",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Livingston/p/15824146.html