码迷,mamicode.com
首页 > 其他好文 > 详细

POJ1043 What's In a Name 逆图+完美匹配

时间:2015-08-16 16:39:39      阅读:132      评论:0      收藏:0      [点我收藏+]

标签:c++

题目链接:

poj1043




题意:

一个犯罪团伙有N个人,他们分别有一个名字和一个网名

现已知他们会先后进出一个房间发送电报

警方可以知道所有时间下:

进出房间的人的真实名字

同时通过截获该房间发出的电报,获得网名

问最后能否将所有真实名字和虚拟网名对上




解题思路:

首先根据题目条件名字和网名是一一对应的,可以大概确定是二分匹配中的完美匹配

然而根据样例很容易看出来,要想根据正确关系来建边是很复杂的

容易的做法是:每次将不可能匹配的名字和网名建边,最后根据补图进行最大匹配即可初步得出所有匹配关系.

但现在得到的最大匹配不一定是完美匹配

要确定某个名字和网名是匹配的 我们可以删除当前已匹配的边,再进行最大匹配

如果结果减小了,则一定是对应的

这样,依次枚举每一条最大匹配中的边.即可得出答案




代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define maxn 25
using namespace std;
struct node
{
    string a,b;
} s[maxn];
map<string,int>m1,m2;
string s1[maxn];
int edge[maxn][maxn];
int link[maxn],vis[maxn];
int mark[maxn];
int id,n;

void init()
{
    memset(edge,0,sizeof(edge));
    memset(mark,0,sizeof(mark));
    id=1;
    m1.clear(),m2.clear();
}

int cmp(node x,node y)
{
    return x.a<y.a;
}

int dfs(int u)
{
    for(int i=1;i<=n;i++)
    {
        if(!vis[i]&&edge[u][i]==0)
        {
            vis[i]=1;
            if(link[i]==-1||dfs(link[i]))
            {
                link[i]=u;
                return 1;
            }
        }
    }
    return 0;
}

int Hungry()
{
    memset(link,-1,sizeof(link));
    int ans=0;
    for(int i=1;i<=n;i++)
        {
            memset(vis,0,sizeof(vis));
            if(dfs(i))
                ans++;
        }
    return ans;
}
int main()
{
    int m,a,b,d;
    char ch;
    string str;
    while(~scanf("%d",&n))
    {
        init();
        for(int i=1; i<=n; i++)
        {
            cin>>s1[i];
            m1[s1[i]]=i;
        }
        while(cin>>ch)
        {
            if(ch=='Q')
                break;
            else
            {
                cin>>str;
                if(ch=='E')
                {
                    if(!m2[str])
                        d=m2[str]=id++;
                    else
                        d=m2[str];
                    mark[d]=1;
                    s[d].a=str;
                    s[d].b="???";
                }
                else if(ch=='L')
                {
                    d=m2[str];
                    mark[d]=0;
                }
                else if(ch=='M')
                {
                    d=m1[str];
                    for(int i=1;i<=n;i++)
                        if(!mark[i])                 //建立反向边
                            edge[d][i]=1;
                }
            }
        }
        int ans=Hungry();
        int linkt[maxn];
        for(int i=1;i<=n;i++)           //原最大匹配中的边
            linkt[i]=link[i];
        for(int i=1;i<=n;i++)
        {
            d=linkt[i];
            edge[d][i]=1;
            if(Hungry()!=ans)           //最大匹配减少 
                s[i].b=s1[d];
            edge[d][i]=0;
        }
//        for(int i=1;i<=n;i++)
//            cout<<s[i].a<<" "<<s1[link[i]]<<endl;
        sort(s+1,s+1+n,cmp);
        for(int i=1;i<=n;i++)
            cout<<s[i].a<<":"<<s[i].b<<endl;
    }
    return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

POJ1043 What's In a Name 逆图+完美匹配

标签:c++

原文地址:http://blog.csdn.net/axuan_k/article/details/47686343

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!