POJ 1043 What's In A Name?(唯一的最大匹配方法)

                                                        What's In A Name?
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 2600   Accepted: 933

Description

The FBI is conducting a surveillance of a known criminal hideout which serves as a communication center for a number of men and women of nefarious intent. Using sophisticated decryption software and good old fashion wiretaps, they are able to decode any e-mail messages leaving the site. However, before any arrest warrants can be served, they must match actual names with the user ID's on the messages. While these criminals are evil, they're not stupid, so they use random strings of letters for
their ID's (no dillingerj ID's found here). The FBI knows that each criminal uses only one ID. The only other information they have which will help them is a log of names of the people who enter and leave the hideout. In many cases, this is enough to link the names to the ID's.

Input

Input consists of one problem instance. The first line contains a single positive integer n indicating the number of criminals using the hideout. The maximum value for n will be 20. The next line contains the n user ID's, separated by single spaces. Next will be the log entries in chronological order. Each entry in the log has the form type arg , where type is either E, L or M: E indicates that criminal arg has entered the hideout; L indicates criminal arg has left the hideout; M indicates a message was intercepted from user ID arg. A line containing only the letter Q indicates the end of the log. Note that not all user ID's may be present in the log but each criminal name will be guaranteed to be in the log at least once. At the start of the log, the hideout is presumed to be empty. All names and user ID's consist of only lowercase letters and have length at most 20. Note: The line containing only the user ID's may contain more than 80 characters.

Output

Output consists of n lines, each containing a list of criminal names and their corresponding user ID's, if known. The list should be sorted in alphabetical order by the criminal names. Each line has the form name:userid , where name is the criminal's name and userid is either their user ID or the string ??? if their user ID could not be determined from the surveillance log.

Sample Input

7 
bigman mangler sinbad fatman bigcheese frenchie capodicapo 
E mugsy 
E knuckles 
M bigman 
M mangler 
L mugsy 
E clyde 
E bonnie 
M bigman 
M fatman 
M frenchie 
L clyde 
M fatman 
E ugati 
M sinbad 
E moriarty 
E booth 
Q 

Sample Output

bonnie:fatman
booth:???
clyde:frenchie
knuckles:bigman
moriarty:???
mugsy:mangler
ugati:sinbad
【题意】一个犯罪团伙有N个人,他们分别有一个名字和一个网名 现已知他们会先后进出一个房间发送电报 警方可以知道所有时间下: 进出房间的人的真实名字 同时通过截获该房间发出的电报,获得网名 问最后
能否将所有真实名字和虚拟网名对上
【分析】首先根据题目条件名字和网名是一一对应的,可以大概确定是二分匹配中的完美匹配 然而根据样例很容易看出来,要想根据正确关系来建边是很复杂的 容易的做法是:每次将不可能匹配的名字和网名建边,
最后根据补图进行最大匹配即可初步得出所有匹配关系.但现在得到的最大匹配不一定是完美匹配 要确定某个名字和网名是匹配的 我们可以删除当前已匹配的边,再进行最大匹配 如果结果减小了,则一定是对应的
这样,依次枚举每一条最大匹配中的边.即可得出答案
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <queue>
#include <vector>
#define inf 0x7fffffff
#define met(a,b) memset(a,b,sizeof a)
typedef long long ll;
using namespace std;
const int N = 35;
const int M = 5005;
int read() {
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9') {
        if(c=='-')f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}
struct man {
    string a,b;
} s[N];
map<string,int>m1,m2;
string s1[N];
int edg[N][N];
int link[N],vis[N];
int mark[N];
int id,n;

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

bool  cmp(man x,man y) {
    return x.a<y.a;
}

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

int MaxMatch() {
    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])m2[str]=id++;
                    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])edg[d][i]=1; //建立反向边
                }
            }
        }
        int ans=MaxMatch();
        int linkt[N];
        for(int i=1; i<=n; i++)         //原最大匹配中的边
            linkt[i]=link[i];
        for(int i=1; i<=n; i++) {
            d=linkt[i];
            edg[d][i]=1;
            if(MaxMatch()!=ans)s[i].b=s1[d];           //最大匹配减少
            edg[d][i]=0;
        }
        sort(s+1,s+1+n,cmp);
        for(int i=1; i<=n; i++)
            cout<<s[i].a<<":"<<s[i].b<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jianrenfang/p/5935520.html