What's In A Name?
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
Source
East Central North America 2001
题目类型:反向构图+删边判断+二分图最大匹配
算法分析:首先这个图明显是一个二分图,这里构造二分图时使用了一个巧妙的方法:反向构造。即先在所有姓名-用户名对之间连边,然后每次在得到邮件信息(比如用户名a)时,将不在藏匿点的姓名和用户名a之间的边删去,最后就留下所有可能的情况。然后枚举每条边并将其删去,判断得到的最大匹配数是否小于没删去之前的最大匹配数。若小于,则说明当前边是一个唯一确定的边。否则当前边是目前还未确定的(注意只是目前还未确定的,有可能之后被唯一确定)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
/************************************************* Author :supermaker Created Time :2016/1/20 14:39:00 File Location :C:\Users\abcd\Desktop\TheEternalPoet **************************************************/ #pragma comment(linker, "/STACK:102400000,102400000") #include <set> #include <bitset> #include <list> #include <map> #include <stack> #include <queue> #include <deque> #include <string> #include <vector> #include <ios> #include <iostream> #include <fstream> #include <sstream> #include <iomanip> #include <algorithm> #include <utility> #include <complex> #include <numeric> #include <functional> #include <cmath> #include <ctime> #include <climits> #include <cstdarg> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <cassert> using namespace std; #define CFF freopen ("aaa.txt", "r", stdin) #define CPPFF ifstream cin ("aaa.txt") #define DB(ccc) cout << #ccc << " = " << ccc << endl #define PB push_back #define MP(A, B) make_pair(A, B) typedef long long LL; typedef unsigned long long ULL; typedef double DB; typedef pair <int, int> PII; typedef pair <int, bool> PIB; const int INF = 0x7F7F7F7F; const int MOD = 1e9 + 7; const double EPS = 1e-10; const double PI = 2 * acos (0.0); const int maxn = 66; string sa[maxn], sb[maxn], cmda[maxn*maxn], cmdb[maxn*maxn]; int g[maxn][maxn], vis[maxn]; int cx[maxn], cy[maxn], cxlen, cylen; int dfs (int u) { for (int v = 1; v <= cylen; v++) if (g[u][v] < INF && !vis[v]) { vis[v] = 1; if (cy[v] == -1 || dfs (cy[v])) { cy[v] = u; cx[u] = v; return 1; } } return 0; } int maxmatch () { int res = 0; memset (cx, -1, sizeof (cx)); memset (cy, -1, sizeof (cy)); for (int i = 1; i <= cxlen; i++) if (cx[i] == -1) { memset (vis, 0, sizeof (vis)); res += dfs (i); } return res; } int main() { //CFF; //CPPFF; int n; while (cin >> n) { for (int i = 1; i <= n; i++) cin >> sa[i]; int len = 0; string tempa, tempb; set <string> seta; cxlen = cylen = 0; while (cin >> tempa) { if (tempa == "Q") break; cin >> tempb; len++; cmda[len] = tempa, cmdb[len] = tempb; if (tempa != "M" && seta.find (tempb) == seta.end ()) { seta.insert (tempb); sb[++cylen] = tempb; } } cxlen = n; // DB (cxlen), DB (cylen); for (int i = 1; i <= cxlen; i++) for (int j = 1; j <= cylen; j++) g[i][j] = 1; seta.clear (); for (int i = 1; i <= len; i++) { if (cmda[i] == "E") seta.insert (cmdb[i]); else if (cmda[i] == "L") seta.erase (cmdb[i]); else if (cmda[i] == "M") { int pos = 1; for (int j = 1; j <= cxlen; j++) if (sa[j] == cmdb[i]) { pos = j; break; } for (int j = 1; j <= cylen; j++) if (seta.find (sb[j]) == seta.end ()) g[pos][j] = INF; } } map <string, string> ans; int org = maxmatch (); for (int i = 1; i <= cxlen; i++) for (int j = 1; j <= cylen; j++) if (g[i][j] == 1) { g[i][j] = INF; int tt = maxmatch (); g[i][j] = 1; if (ans.find (sb[j]) != ans.end () && ans[sb[j]] != "???") continue; if (tt < org) ans[sb[j]] = sa[i]; else ans[sb[j]] = "???"; // DB (i), DB (j), DB (tt), DB (sb[j]), DB (sa[i]), DB (ans[sb[j]]), cout << endl; } for (map <string, string> :: iterator it = ans.begin (); it != ans.end (); it++) cout << it -> first << ":" << it -> second << endl; //cout << endl; } return 0; } |