PAT L2-016. 愿天下有情人都是失散多年的兄妹 (BFS)

L2-016. 愿天下有情人都是失散多年的兄妹

时间限制
200 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
陈越

呵呵。大家都知道五服以内不得通婚,即两个人最近的共同祖先如果在五代以内(即本人、父母、祖父母、曾祖父母、高祖父母)则不可通婚。本题就请你帮助一对有情人判断一下,他们究竟是否可以成婚?

输入格式:

输入第一行给出一个正整数N(2 <= N <= 104),随后N行,每行按以下格式给出一个人的信息:

本人ID 性别 父亲ID 母亲ID

其中ID是5位数字,每人不同;性别M代表男性、F代表女性。如果某人的父亲或母亲已经不可考,则相应的ID位置上标记为-1。

接下来给出一个正整数K,随后K行,每行给出一对有情人的ID,其间以空格分隔。

注意:题目保证两个人是同辈,每人只有一个性别,并且血缘关系网中没有乱伦或隔辈成婚的情况。

输出格式:

对每一对有情人,判断他们的关系是否可以通婚:如果两人是同性,输出“Never Mind”;如果是异性并且关系出了五服,输出“Yes”;如果异性关系未出五服,输出“No”。

输入样例:
24
00001 M 01111 -1
00002 F 02222 03333
00003 M 02222 03333
00004 F 04444 03333
00005 M 04444 05555
00006 F 04444 05555
00007 F 06666 07777
00008 M 06666 07777
00009 M 00001 00002
00010 M 00003 00006
00011 F 00005 00007
00012 F 00008 08888
00013 F 00009 00011
00014 M 00010 09999
00015 M 00010 09999
00016 M 10000 00012
00017 F -1 00012
00018 F 11000 00013
00019 F 11100 00018
00020 F 00015 11110
00021 M 11100 00020
00022 M 00016 -1
00023 M 10012 00017
00024 M 00022 10013
9
00021 00024
00019 00024
00011 00012
00022 00018
00001 00004
00013 00016
00017 00015
00019 00021
00010 00011
输出样例:
Never Mind
Yes
Never Mind
No
Yes
No
Yes
No
No

这题是基础bfs,不过题目有点坑。

解题思路:因为该题说明不会出现乱伦,且只能同辈结婚。所以我们可以直接设个vis数组记录点是否重复出现就行了,如果重复出现,则肯定是近亲或者同性了。

1.注意初始化每个节点的父母,不然搜到一个点没有给出其父母,继续搜索下去,会得到初始化的值0,若有两个以上没有父母,则0会重复出现,导致误判。
2.父母也有可能同性。

这两点样例中都有体现,基本样例过了,该题就过了。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <string>
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <vector>
 7 #include <map>
 8 #include <queue>
 9 #include <map>
10 #include <cmath>
11 using namespace std;
12 const int inf = 0x3f3f3f3f;
13 typedef long long ll;
14 const int maxn = 1e5+10;
15 struct nod
16 {
17     int sex;
18     int fid;
19     int mid;
20 };
21 int vis[maxn];//记录是否重复出现
22 int cnt[maxn];//判断搜到了第几代
23 map<int,nod>mp;//map存id
24 void bfs(int u,int v)
25 {
26     memset(vis,0,sizeof(vis));
27     memset(cnt,0,sizeof(cnt));
28     queue<int>q;
29     q.push(u);
30     q.push(v);
31     while(!q.empty())
32     {
33         int x=q.front();q.pop();
34         if(vis[x])
35         {
36     //        cout<<x<<endl;
37             puts("No");
38             return ;
39         }
40         vis[x]=1;
41         if(cnt[x]<4)
42         {
43             u=mp[x].fid;
44             v=mp[x].mid;
45             if(u!=-1)
46             {
47                 q.push(u);
48                 cnt[u]=cnt[x]+1; 
49             }
50             if(v!=-1)
51             {
52                 q.push(v);
53                 cnt[v]=cnt[x]+1;
54             }
55         }
56 
57     }
58     puts("Yes");
59 }
60 int main()
61 {
62 
63     int n;
64     scanf("%d",&n);
65     int a,c,d;
66     char b;
67     for(int i=0;i<1e5+10;++i) //父母初始化
68     mp[i].fid=-1,mp[i].mid=-1;
69     for(int i=0;i<n;++i)
70     {
71         scanf("%d %c %d %d",&a,&b,&c,&d);
72         if(b=='M') mp[a].sex=1;
73         else mp[a].sex=0;
74         mp[a].fid=c;
75         mp[c].sex=1; //存储其父母的性别
76         mp[a].mid=d;
77         mp[d].sex=0;
78     }
79     int k;
80     scanf("%d",&k);
81     int u,v;
82     for(int i=0;i<k;++i)
83     {
84         scanf("%d%d",&u,&v);
85         if(mp[u].sex==mp[v].sex)    puts("Never Mind");
86         else   bfs(u,v);
87     }
88     return 0;
89 }
View Code

 

反思:这道题单拉出来写,会觉得很简单,因为思路很清晰,cccc的题大多是这样。但是比赛的时候就没写出来,写出的代码又臭又长。赛后经过思考,我认为是因为比赛的时候有大量的题,而且前面的题都是手速题,很容易为了赶时间 而陷入 靠直觉狂敲不思考的状态。但是后面的搜索与图论题,动动脑筋会让代码简洁许多,想出完整的思路再敲才是高效的方法。

因此在以后比赛中要学会暂停,时间再紧张,也要休息。

卡题超过半个小时,就应该赶紧换题。


posted @ 2018-03-05 23:30  euzmin  阅读(426)  评论(0编辑  收藏  举报