codevs 1027 姓名与ID
1027 姓名与ID
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 大师 Master
题目描述 Description
有N个人,各自有一个姓名和ID(别名)。每个人的姓名和ID都没有重复。这些人依次进入一间房间,然后可能会离开。过程中可以得到一些信息,告知在房间里的某个人的ID。你的任务是准确地确定每个人的ID。
输入描述 Input Description
第一行是整数N,表示N个人,N<=20。
接下来的一行是N个人的ID,用一个空格分隔。
接下来的若干行是过程的记录:一个字母和一个字符串。字母是E、L或M中的一个。E表示进入房间,后面跟的字符串表示进来的人的姓名;L表示离开房间,后面跟的字符串表示离开的人的姓名;M表示回答询问,后面跟的字符串表示:当前用这个ID人在房间里面。
最后一行Q表示结束。
所有的姓名和ID都由不超过20个的小写字母组成。所有姓名都会在记录中出现。
一开始时,房间时空的。
输出描述 Output Description
共N行,每行形如:“姓名:ID”,如果ID不能确定,输出???。
按照姓名的字典顺序输出。
样例输入 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
数据范围及提示 Data Size & Hint
/* 什么都没用结果得了90分 求错误在那?????? 正解 二分图匹配 在下面 */ #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<map> #include<algorithm> using namespace std; int n,tot,topt,g[50],a[50][50],sum[50]; string s[50]; string ss[50]; map<string,int>p; map<string,int>f; queue<int>q; struct node { string xingming; string ID; }fin[50]; int cmp(node x,node y) { return x.xingming<y.xingming; } int main() { int i,j,k; cin>>n; for(i=1;i<=n;i++) { cin>>s[i]; sum[i]=n; f[s[i]]=i; } char c; while(1) { cin>>c; if(c=='Q')break; if(c=='E') { string st; cin>>st; if(p[st]==0) { ss[++tot]=st; p[st]=tot; } g[p[st]]=1; } if(c=='L') { string st; cin>>st; g[p[st]]=0; } if(c=='M') { string st; cin>>st; int t=f[st]; for(i=1;i<=n;i++) { if(i>tot||g[i]==0||a[i][t]==1) { if(a[i][t]==0)sum[t]--; a[i][t]=1; } } } } for(i=1;i<=n;i++) if(sum[i]==1) q.push(i); while(!q.empty()) { int d=q.front(); q.pop(); for(i=1;i<=n;i++) if(a[i][d]==0) { for(j=1;j<=n;j++) if(j!=d) { if(a[i][j]==0) { sum[j]--; if(sum[j]==1)q.push(j); } a[i][j]=1; } } } for(i=1;i<=n;i++) { fin[i].xingming=ss[i]; int flag=0; for(j=1;j<=n;j++) if(a[i][j]==0&&sum[j]==1) { fin[i].ID=s[j]; flag=1; } if(flag==0)fin[i].ID="???"; } sort(fin+1,fin+n+1,cmp); for(i=1;i<=n;i++) cout<<fin[i].xingming<<":"<<fin[i].ID<<endl; return 0; }
/* 二分图匹配 刚开始每个人和每个ID都连一条边 刚开始都有可能 有一个数组记录是否在房间内 当E和L操作时更新此数组 当M时 把此时的ID和不在房间内的人边取消掉 结束后 把现在还连着的边取消掉 看看是否能完没匹配 若不能 则说明这条边应该连 记录这条边两边的姓名与ID */ #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<map> #include<algorithm> using namespace std; int n,tot,topt,g[50],a[50][50],match[50],ff[50]; string s[50]; string ss[50]; map<string,int>p; map<string,int>f; queue<int>q; struct node { string xingming; string ID; }fin[50]; int cmp(node x,node y) { return x.xingming<y.xingming; } int dfs(int x) { for(int i=1;i<=n;i++) { if(a[x][i]==0&&!ff[i]) { ff[i]=1; if(!match[i]||dfs(match[i])) { match[i]=x; return 1; } } } return 0; } int main() { int i,j,k; cin>>n; for(i=1;i<=n;i++) { cin>>s[i]; f[s[i]]=i; } char c; while(1) { cin>>c; if(c=='Q')break; if(c=='E') { string st; cin>>st; if(p[st]==0) { ss[++tot]=st; p[st]=tot; } g[p[st]]=1; } if(c=='L') { string st; cin>>st; g[p[st]]=0; } if(c=='M') { string st; cin>>st; int t=f[st]; for(i=1;i<=n;i++) if(g[i]==0) a[i][t]=1; } } for(i=1;i<=n;i++) { int flag=0; fin[i].xingming=ss[i]; for(j=1;j<=n;j++) if(a[i][j]==0) { a[i][j]=1; int sum=0; memset(match,0,sizeof(match)); for(k=1;k<=n;k++) { memset(ff,0,sizeof(ff)); if(dfs(k)) sum++; } if(sum<n) { fin[i].ID=s[j]; flag=1; a[i][j]=0; break; } a[i][j]=0; } if(!flag)fin[i].ID="???"; } sort(fin+1,fin+n+1,cmp); for(i=1;i<=n;i++) cout<<fin[i].xingming<<":"<<fin[i].ID<<endl; return 0; }