codevs姓名与id


  1. 有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

     

    此题难在构造,,这点做好了数据还是比较小的。。。姓名和id可以用map容器解决。。但是关键在于构图,,不能只把在里面的姓名和提示id连边。。因为有些id不一定会出现。。。而应该用排除法,,先假设全部两两相连。然后删去不在里面的姓名和提示id的边,这样才能做到全面。。最后判断这条匹配是否唯一,可以用下面代码中的找回路。。但我觉得也可以删去这条边重新做一次二分图判断是否还能完成最大匹配。
  2. #include<iostream>  
  3. #include<cstdio>  
  4. #include<cstring>  
  5. #include<algorithm>  
  6. #include<map>  
  7. #include<set>  
  8. using namespace std;  
  9. int n;  
  10. int line[30][30];  
  11. int b[30],g[30];  
  12. bool used[30];  
  13. map<string,int>name;  
  14. string na[30];  
  15. map<string,int>id;  
  16. string di[30];  
  17. set<int>se;  
  18. set<int>leave;  
  19. bool vis[30];  
  20. struct Node  
  21. {  
  22.     string name,id;  
  23.     bool operator<(const Node& u)const  
  24.     {  
  25.         return name<u.name;  
  26.     }  
  27. };  
  28. Node p[30];  
  29. int e=0;  
  30.   
  31.   
  32. bool find(int x);  
  33. bool check(int x);  
  34. int main()  
  35. {  
  36.     memset(b,0,sizeof(b));  
  37.     memset(g,0,sizeof(g));  
  38.     string str;  
  39.     char ch[2];  
  40.     scanf("%d",&n);  
  41.     for(int i=0;i<n;i++){  
  42.         cin>>str;  
  43.         id[str]=i+1;  
  44.         di[i+1]=str;  
  45.         leave.insert(i+1);  
  46.     }  
  47.     int o=1;  
  48.     for(int i=1;i<=n;i++){  
  49.         for(int j=1;j<=n;j++)  
  50.             line[i][j]=1;  
  51.     }  
  52.     while(~scanf("%s",ch)){  
  53.         if(ch[0]=='Q')  
  54.             break;  
  55.         cin>>str;  
  56.         if(ch[0]=='E'){  
  57.             if(name[str]==0){  
  58.                 name[str]=o++;  
  59.                 na[o-1]=str;  
  60.             }  
  61.             se.insert(name[str]);  
  62.             leave.erase(name[str]);  
  63.         }  
  64.         else if(ch[0]=='L'){  
  65.             leave.insert(name[str]);  
  66.             se.erase(name[str]);  
  67.         }  
  68.         else{  
  69.             int k=id[str];  
  70.             for(set<int>::iterator it=leave.begin();it!=leave.end();it++){  
  71.                 line[*it][k]=0;  
  72.             }  
  73.         }  
  74.     }  
  75.     for(int i=1;i<=n;i++){  
  76.         memset(used,0,sizeof(used));  
  77.         find(i);  
  78.     }  
  79.     for(int i=1;i<=n;i++){  
  80.         memset(vis,0,sizeof(vis));  
  81.         memset(used,0,sizeof(used));  
  82.         if(check(i)){  
  83.             p[e].name=na[i];  
  84.             p[e++].id="???";  
  85.         }  
  86.         else{  
  87.             p[e].name=na[i];  
  88.             p[e].id=di[b[i]];  
  89.             e++;  
  90.         }  
  91.     }  
  92.     sort(p,p+e);  
  93.     for(int i=0;i<e;i++)  
  94.         cout<<p[i].name<<":"<<p[i].id<<endl;  
  95.     return 0;  
  96. }  
  97.   
  98. bool find(int x)  
  99. {  
  100.     for(int i=1;i<=n;i++){  
  101.         if(line[x][i]==1&&used[i]==0){  
  102.             used[i]=1;  
  103.             if(g[i]==0||find(g[i])){  
  104.                 b[x]=i;  
  105.                 g[i]=x;  
  106.                 return true;  
  107.             }  
  108.         }  
  109.     }  
  110.     return false;  
  111. }  
  112. //判断x能不能有别的匹配  
  113. bool check(int x)  
  114. {  
  115.     if(vis[x]==1)//走出回路  
  116.         return true;  
  117.     vis[x]=1;  
  118.     for(int i=1;i<=n;i++){  
  119.         if(used[i]==0&&line[x][i]&&g[i]!=x){//不是原匹配  
  120.             used[i]=1;  
  121.             if(g[i]==0||check(g[i]))  
  122.                 return true;  
  123.         }  
  124.     }  
  125.     return false;  
  126. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值