题目来源:http://poj.org/problem?id=1043

题目大意:

  一个犯罪团伙有n个成员,每人有一个唯一的字符串作为id,每人还有一个唯一的字符串作为name。该团伙有一个hideout系统,成员利用这个系统进行通信。成员进入hideout后可以发出信息,发出的信息会留下发送者的id。现在FBI获得了hideout的log记录,包括成员进入和离开的记录以及系统中发送信息的记录。其中,成员进入和离开记录的是他们的name,发送的信息记录的是id。成员只有在hideout中才能发送信息。整个log中每个成员至少出现一次,但不一定每个人都会发送信息。FBI希望通过这些记录确定犯罪团伙中每个成员的name和id的匹配关系。hideout初始时视为没有人。

输入:由单个测试用例组成。第一行整数n表示人数。第二行n个字符串表示每个人的id。接下来的每行为一条记录。由一个字符和一个字符串组成。‘E’表示进入,‘L’表示离开,后面的字符串是该人的name,‘M’表示发送了一条信息,后面接发送人id。‘Q’表示结束。

输出:输出由n行组成,每行输出name:id的匹配对,若某个name无法确定其id输出name:???。按name字典序输出。


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

该题与二部图的匹配问题紧密相关。之前的一篇博客已经介绍过了这道题里要用到的与二部图相关的理论基础。

请戳:http://www.cnblogs.com/dengeven/p/3230406.html

但是仅仅意识到与二部图匹配有关还不足以解决问题,因为我们要找的是确定会出现在完全匹配中的边。

首先,图的建立就是有小技巧的。如果按log顺序处理,每发出一条信息,连接在hideout中的name与信息显示的id,当有人离开发现矛盾再删除边这样的策略的话,可能被漏掉的情况很多,因为有人可能没有发出信息,即有的id不会显示在log中。简便的处理方法是初始时把所有连接都设为true,当出现一条信息时,删掉该id与不在hideout中的name的连接。这样就不会漏掉边。

然后,因为id与name是一一对应的,其实也就是说图应该有唯一的完全匹配,匹配数为n。确定每个name对于的id的方法是:遍历与name相接的每条边,如果去掉该条边,剩余图的最大匹配数小于n,说明这条边一定是唯一完全匹配中的,即与该name匹配的id可以确定,否则无法确定。

 //////////////////////////////////////////////////////////////////////////
// POJ1043 What's In A Name
// Memory: 252K Time: 16MS
// Language: C++ Result: Accepted
////////////////////////////////////////////////////////////////////////// #include <cstring>
#include <iostream>
#include <algorithm> using namespace std; int n; //人数
char id[][]; //记录每个id
char name[][]; //记录每个name
int order[]; //name字典序序号
bool in_hideout[];//in_hideout[i]为true表示第i个人在hideout内
bool graph[][]; //graph[i][j]为true表示第i个name与第j个id有可能匹配
int link_name[]; //link_name[i]:匹配中与id为i的顶点相连的name编号
bool visited[]; //顶点访问标记数组
int match_id[]; //match_id[i]为确定后第i个name匹配的id号,不确定的为-1 inline int cmp(int i,int j){
if (memcmp(name[i],name[j],sizeof name[i]) <= ) return ;
else return ;
} //dfs寻找增广路
int findPath(int k){
for (int i = ; i < n; ++i) {
if (graph[k][i] && visited[i] == false){
visited[i] = true;
if (link_name[i] == - || findPath(link_name[i])){
link_name[i] = k;
return ;
}
}
}
return ;
} //匈牙利算法求最大匹配
int hungary(){
int cnt = ;
memset(link_name,-,sizeof(link_name));
for (int i = ; i < n; ++i) {
memset(visited, , sizeof(visited));
cnt += findPath(i);
}
return cnt; //最大匹配数
} int main(){
cin >> n;
for (int i = ; i < n; ++i) cin >> id[i];
memset(graph, true, sizeof(graph));
memset(match_id, -, sizeof(match_id));
memset(in_hideout, false, sizeof(in_hideout));
int name_cnt = ;
char log_type;
char buf[];
while (true) {
cin >> log_type;
if (log_type == 'Q') break;
cin >> buf;
int i;
switch (log_type){
case 'E':
for (i = ; i < name_cnt && strcmp(buf, name[i]) != ; ++i);
if (i == name_cnt) {
strcpy(name[name_cnt++], buf);
}
in_hideout[i] = ;
break;
case 'L':
for (i = ; i < name_cnt && strcmp(buf, name[i]) != ; ++i);
in_hideout[i] = ;
break;
case 'M':
for (i = ; i < n && strcmp(buf,id[i]) != ; ++i);
for (int j = ; j < n; ++j) {
if (!in_hideout[j]) {
graph[j][i] = false;
}
}
break;
}
}
for (int i = ; i < n; ++i){
for (int j = ;j < n; ++j) {
if (graph[i][j]) {
graph[i][j] = false;
if (hungary() != n) {
//该边是最大匹配的必须边,是确定的匹配
graph[i][j] = true;
match_id[i] = j;
break;
}
graph[i][j] = true;
}
}
}
for (int i = ; i < n; ++i) order[i] = i; //按name字典序输出
sort(order,order + n,cmp);
for (int i = ;i < n;i ++){
cout << name[order[i]] << ":";
if (match_id[order[i]] == -) {
cout << "???" << endl;
} else {
cout << id[match_id[order[i]]] << endl;
}
}
system("pause");
return ;
}

POJ1043 What's In A Name?的更多相关文章

  1. POJ1043问题描述

    Description The FBI is conducting a surveillance of a known criminal hideout which serves as a commu ...

随机推荐

  1. redis学习--String数据类型。

    本文摘自:http://www.cnblogs.com/stephen-liu74/archive/2012/03/14/2349815.html 一.概述: 字符串类型是Redis中最为基础的数据存 ...

  2. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...

  3. android开发之Bitmap 、byte[] 、 Drawable之间的相互转换

    一.相关概念 1.Drawable就是一个可画的对象,其可能是一张位图(BitmapDrawable),也可能是一个图形(ShapeDrawable),还有可能是一个图层(LayerDrawable) ...

  4. java对象在内存中的结构(HotSpot虚拟机)

    一.对象的内存布局 HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header).实例数据(Instance Data)和对齐填充(Padding). 从上面的这张图里面可以 ...

  5. DCloud-MUI:Hello MUI2

    ylbtech-DCloud: 1. <head> <meta charset="utf-8"> <title>Hello MUI</ti ...

  6. Java中Redis入门(1)

    Redis是一个开源的,先进的 key-value 存储可用于构建高性能,可扩展的 Web 应用程序的解决方案. Redis官方网网站是:http://www.redis.io/,如下: Redis ...

  7. SpringMvc之参数绑定注解详解之三

    2. @RequestHeader.@CookieValue @RequestHeader 注解,可以把Request请求header部分的值绑定到方法的参数上. 示例代码: 这是一个Request ...

  8. 请定义一个宏,比较两个数的a、b的大小,不能使用大于、小于、if语句

    请定义一个宏,比较两个数的a.b的大小,不能使用大于.小于.if语句 方法一:    #define max(a,b) ((((long)((a)-(b)))&0x80000000)?(b): ...

  9. [xjtu21]wmq的午餐 计数问题

    http://oj.xjtuacm.com/problem/21/ 对13进行分析,每种价格出现的次数: $(C_m^1 + C_m^2 + ... + C_m^m)(C_{n - m}^0 + C_ ...

  10. JDBC编程之数据查询

    ----------------siwuxie095                             JDBC 编程之数据查询             首先下载 MySQL 的 JDBC 驱动 ...