POJ1043 What's In A Name?
题目来源: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?的更多相关文章
- POJ1043问题描述
Description The FBI is conducting a surveillance of a known criminal hideout which serves as a commu ...
随机推荐
- 说几个JS优化技巧吧
JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML(标 ...
- JZOJ 1003【东莞市选2007】拦截导弹——dp
题目:https://jzoj.net/senior/#main/show/1003 只要倒推一下第一次上升的最长和第一次下降的最长就行了.不用n^2logn,枚举了 j 还要用树状数组找值比自己大的 ...
- 获得Azure订阅LoadBalancer的脚本
有客户希望可以通过一条命令获得一个Azure订阅中所有的负载均衡器. 目前在Azure的powershell中是没有这中命令的.但我们可以通过脚本的方式实现. 下面就是获得所有负载均衡的脚本: par ...
- 【转】Unity3D如何制作落叶效果
原文地址:http://hi.baidu.com/cupgenie/item/c23861df692f59e3b3f777a8 创建一个粒子系统 GameObject>Create other& ...
- Python:os.walk()和os.path.walk()用法
转于:https://www.cnblogs.com/zmlctt/p/4222621.html 博主:zmlctt 一.os.walk() 函数声明:os.walk(top,topdown=True ...
- MyEclipse 手动安装Velocity 编辑器
最近项目有使用Velocity 模板引擎,从而会用到*.VM页面!Myeclipse打开VM页面字体一片漆黑,哪有JSP那样看起来舒服(个人感觉)!为了解决这一问题就要安装Velocity编辑器,安装 ...
- 使用jquery扩展表格行合并方法探究
1.前言 最近项目中用到一个表格中对于相同内容的数据进行行合并的需求,本来想从网上找个现成的,省的自己再造轮子.于是就开始谷歌了...不过在搜索的过程中,发现找到的工具类很多都有一个前提,就是该表格中 ...
- Android源码中添加APP
参考罗升阳<Android系统源代码情景分析> 在Android源码中,我们通常把实验性质的Android APP放在packages/experimental目录下.对于一个简单的应用程 ...
- Debian安装Docker
Debian 安装 Docker CE 准备工作 系统要求 Docker CE 支持以下版本的 Debian 操作系统: Stretch 9 Jessie 8 (LTS) Wheezy 7.7 (LT ...
- hadoop主节点(NameNode)备份策略以、恢复方法、操作步骤
一.dits和fsimage 首先要提到两个文件edits和fsimage,下面来说说他们是做什么的. 集群中的名称节点(NameNode)会把文件系统的变化以追加保存到日志文件edits中 ...