二分图匹配:what is in your name

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

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


题目大意:

坏人有网名和真名,知道他们真名离开和进入房间的时间

也知道他们网名的发言时间,求网名和真名的匹配

实际上就是二分图匹配,首先默认所有点都是相连的,再通过他们的进出时间排除所有不可能的情况,再匈牙利算法匹配


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

using namespace std;

int n ;
int sum = 0; //进去的人的数目
int is_in[25] ;
char name[25][25], id[25][25];
int g[25][25]; //前一项表示人名,后一项表示网名
int inde[25];  //表示人名i能与网名inde[i]匹配,如不能,则为-1
int r[25]; //排序时用的序数

const int MAXN = 25;
int uN,vN;
int linker[MAXN];
bool used[MAXN];
bool dfs(int u){
    int v;
    for(v=0;v<vN;v++)
        if(g[u][v]&&!used[v]){
            used[v]=true;
            if(linker[v]==-1||dfs(linker[v])){
                linker[v]=u;
                return true;
            }
        }
    return false;
}

int hungary(){
    int res=0;
    int u;
    memset(linker,-1,sizeof(linker));
    for(u=0;u<uN;u++){
        memset(used,0,sizeof(used));
        if(dfs(u))  res++;
    }
    //cout << "res=" << res << endl;
    return res;
}

void solve(){
    int i, j, k;
    for(i = 0; i < n; i ++){
        for(j = 0; j < n; j ++){
            if(g[i][j]){
                g[i][j] = 0;
                if(hungary() < n){
                    g[i][j] = 1;
                    break;
                }
                g[i][j] = 1;
            }
        }
        //cout << "j=" << j << endl;
        if(j == n){
            inde[i] = -1;
        }
        else{
            inde[i] = j;
        }
    }
}

    inline int cmp(int i,int j){
       if (memcmp(name[i],name[j],sizeof name[i]) <= 0) return 1;
       else return 0;
    }

int main(){
    int i, j, k;
    scanf("%d", &n);
    uN = n;
    vN = n;
    int sum = 0;//房间里人数量
    memset(g, 1, sizeof(g));
    for(i = 0; i < n; i ++){
        scanf("%s", id[i]);
    }
    scanf("\n");
    char tmp;
    char stmp[25];
    for (scanf("%c",&tmp); tmp != 'Q'; scanf("%c",&tmp)){
        scanf("%s\n", stmp);
        switch(tmp){
            case 'E':
                for(i = 0; i < sum; i ++){
                    if(strcmp(stmp, name[i]) == 0)
                        break;
                }
                if(i == sum)
                    strcpy(name[sum ++], stmp);
                is_in[i] = 1;
                break;
            case 'L':
                for(i = 0; i < sum; i ++){
                    if(strcmp(stmp, name[i]) == 0)
                        break;
                }
                is_in[i] = 0;
                break  ;
            case 'M':
                for(i = 0; i < n; i ++){
                    if(strcmp(stmp, id[i]) == 0)
                        break;
                }
                for(j = 0; j < n; j ++){
                    if(!is_in[j])
                        g[j][i] = 0; //排除所有不可能情况,注意i,j不要写反
                }
                break   ;
        }
    }
    solve();
    for(i = 0; i < n; i ++){
        r[i] = i;
    }
    sort(r, r + n, cmp);
    for(i = 0; i < n; i ++){
        printf("%s:", name[r[i]]);
        if(inde[r[i]] == -1)
            printf("???\n" )  ;
        else
            printf("%s\n", id[inde[r[i]]]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值