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;
}

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

时间: 2025-01-24 05:55:05

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

C#生成唯一值的方法汇总

生成唯一值的方法很多,下面就不同环境下生成的唯一标识方法一一介绍,作为工作中的一次总结,有兴趣的可以自行测试: 一.在 .NET 中生成 1.直接用.NET Framework 提供的 Guid() 函数,此种方法使用非常广泛.GUID(全局统一标识符)是指在一台机器上生成的数字,它保证对在同一时空中的任何两台计算机都不会生成重复的 GUID 值(即保证所有机器都是唯一的).关于GUID的介绍在此不作具体熬述,想深入了解可以自行查阅MSDN.代码如下: 1 using System; 2 usi

POJ 1845-Sumdiv(快速幂取模+整数唯一分解定理+约数和公式+同余模公式)

Sumdiv Time Limit:1000MS     Memory Limit:30000KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 1845 Appoint description:  System Crawler  (2015-05-27) Description Consider two natural numbers A and B. Let S be the sum of all natural d

POJ 1849 Two (树形dp 树的直径 两种方法)

Two Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 1232   Accepted: 619 Description The city consists of intersections and streets that connect them. Heavy snow covered the city so the mayor Milan gave to the winter-service a list of st

STM32全球唯一ID读取方法

产品唯一的身份标识非常适合:● 用来作为序列号(例如USB字符序列号或者其他的终端应用)● 用来作为密码,在编写闪存时,将此唯一标识与软件加解密算法结合使用,提高代码在闪存存储器内的安全性.● 用来激活带安全机制的自举过程96位的产品唯一身份标识所提供的参考号码对任意一个STM32微控制器,在任何情况下都是唯一的.用户在何种情况下,都不能修改这个身份标识.这个96位的产品唯一身份标识,按照用户不同的用法,可以以字节(8位)为单位读取,也可以以半字(16位)或者全字(32位)读取.基地址:0x1F

产生唯一随机码的方法分析

现在的WEB中经常会需要产生一些邀请码.激活码.需要是唯一并且随机的.下面总结下一些常用的产生随机码的方法,并分享自己的1个方法: 1. 自己写代码产生随机的数字和字母组合,每产生1个去数据库查询该随机码是否已存在,如果已存在,则重新产生,直到不重复为止. 优点:没发现有啥优点. 缺点:产生速度慢,还要查询数据库,当数据量大的时候,可能重复的机率会比较高,要查询多次数据库.2. guid,该方法应该是用的比较多的. 优点:使用简单方便,不用自己编写额外的代码 缺点:占用数据库空间相对较大,特别是

oracle数据库出现“批处理中出现错误: ORA-00001: 违反唯一约束条件”解决方法

最近使用oraclede impdp工具全库导入数据库时,在数据库里面使用出现如下情况. SQL state [null]; error code [17081]; 批处理中出现错误: ORA-00001: 违反唯一约束条件 (GDXAORCL.SYS_C0055359) ; nested exception is java.sql.BatchUpdateException: 批处理中出现错误: ORA-00001: 违反唯一约束条件 (GDXAORCL.SYS_C0055359) -(:155

winform弹出唯一窗体的方法

Form1中btn1按钮点击show出Form2,当Form2处于开启状态时,再次点击btn1不会继续弹出窗体,而是将焦点定位至已开启的Form2上:当Form2关闭后,再次点击btn1则会show出一个新的Form2: Form1: //创建一个全局集合,用来放置已经show出的窗体对象 List<Form> list = new List<Form>(); //btn1点击事件: private void button1_Click(object sender, EventAr

一个生成唯一GUID的方法

function create_guid(){ $id = strtoupper(md5(uniqid(mt_rand(),true))); $h = chr(45);//"_" $tid = chr(123)//"{" .substr($id,0,8).$h .substr($id,8,4).$h .substr($id,12,4).$h .substr($id,16,4).$h .substr($id,20,12) .chr(125);//"}&quo

POJ 3318-Matrix Multiplication(压缩矩阵用o(n^2)的方法求矩阵相等)

题目地址:POJ 3318 题意:有3个n*n的矩阵A,B,C,问AB是否等于C. 思路:题目描述很简单,就是用矩阵乘法,但是很明显矩阵乘法的时间复杂度为O(n^3),很明显超时.那怎么改进呢?就是用压缩矩阵的方法: 设矩阵R是1*n的矩阵,根据矩阵的性质,若A*B*R=C*R,那么A*B=C.由此可以看出来,虽然多成了一个矩阵,但是时间复杂度成了O(n^2).那么问题是这个R的行列式该怎么设定,有人用的随机算法,但是随机算法可能在关键点上出现错误,可以将R设定成一个递增的数列{1,2,3--}