2007 Simulation message

题目

问题描述:

兴趣小组的同学来自各个学校,为了增加友谊,晚会上又进行了一个传话游戏,如果a认识b,那么a收到某个消息,就会把这个消息传给b,以及所有a认识的人。

如果a认识b,b不一定认识a。

所有人从1到n编号,给出所有’认识’关系,问如果i发布一条新消息,那么会不会经过若干次传话后,这个消息传回给了i(1in)。

 

输入格式:

第一行是两个数n(n<1,000)和m(m<10,000),两数之间有一个空格,表示人数和认识关系数。

接下来的m行,每行两个数a和b,表示a认识b。(1a,bn)。认识关系可能会重复给出,但一行的两个数不会相同。

 

输出格式:

一共有n行,每行一个字符T或F。第i行如果是T,表示i发出一条新消息会传回给i;如果是F,表示i发出一条新消息不会传回给i。

 

样例输入输出:

message.in

4 6

1 2

2 3

4 1

3 1

1 3

2 3

 

message.out

T

T

T

F

 

分析

这道题明显就是要找一个关系环,也就是找一个人到另一个人最后回到最初那个人的环。找环显然用拓扑。这道题当中用了一个小技巧,我们用了两次相对的循环,一次针对入度,一次针对出度,然后没有vis标记过的就是在环上的点。(很聪明的办法)为什么会用到这样双向的拓扑,是因为如果只按照入度来做,就有可能有被包围在环当中的点被忽略了,所以从出度的角度由内向外再扫一遍保证答案正确。

注意数据大小!别乱开数组大小!当主程序return一个很大的值的时候注意检查数组大小!

程序

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int MAXN = 1005;
 4 int n, m, u, v, dg[MAXN], og[MAXN];
 5 vector<int> a[1005],b[1005];
 6 bool g[MAXN][MAXN], vis[MAXN];
 7 queue<int> S;
 8 int main()
 9 {
10     freopen("message.in","r",stdin);
11     freopen("message.out","w",stdout);
12     cin >> n >> m;
13     for (int i = 1; i <= m; i++)
14     {
15         scanf("%d%d",&u,&v);
16         if (!g[u][v])
17         {
18             dg[v]++, og[u]++;
19             g[u][v] = true;
20             a[u].push_back(v);
21             b[v].push_back(u);
22         }
23     }
24     for (int i = 1; i <= n; i++)
25         if (!dg[i])
26             S.push(i);
27     while (!S.empty())
28     {
29         int temp = S.front();
30         S.pop();
31         vis[temp] = true;
32         for (int i = 0; i < a[temp].size(); i++)
33         {
34             dg[a[temp][i]]--;
35             if (!dg[a[temp][i]])
36                 S.push(a[temp][i]);
37         }
38     }
39     for (int i = 1; i <= n; i++)
40         if (!og[i])
41             S.push(i);
42     while (!S.empty())
43     {
44         int temp = S.front();
45         S.pop();
46         vis[temp] = true;
47         for (int i = 0; i < b[temp].size(); i++)
48         {
49             og[b[temp][i]]--;
50             if (!og[b[temp][i]])
51                 S.push(b[temp][i]);
52         }
53     }
54     for (int i = 1; i <= n; i++)
55         if (!vis[i])
56             printf("T\n");
57         else
58             printf("F\n");
59     return 0;
60 }

 

转载于:https://www.cnblogs.com/OIerPrime/p/9325687.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值