落谷 P2661 信息传递

题意很清楚,求图中最小的环。

用dfs来找环,当找到环之后回溯来确定长度,最后比较。

如果一个人的入度为0,则肯定不可能成环,那么把这个人和他连出的边删去(即标记这个人并将他下一个人的入度减 1),如果下一个人的入度为0则将他也删去……最后
把所有入度为0的人都删去了,剩下的都是环。

每个人的出度为1,所以每个人只能在一个环中,每条边只能在一个环中,也就是说每个环都是分开的,然后进行一遍 dfs,找出最小的环。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 int n,t[200050],d[200050],ans=1000000000,r[200050];
 6 void read(int& x) {                                 //快速读入(不会的同学可以直接用cin) 
 7     x=0;
 8     int y=1;
 9     char ch=getchar();
10     while (ch<'0'||ch>'9') {
11         if (ch=='-') y=-1;
12         ch=getchar();
13     }
14     while (ch>='0'&&ch<='9') {
15         x=x*10+ch-'0';
16         ch=getchar();
17     }
18     x=x*y;
19 }
20 void dfs(int ti,int s,int l) {                         //l记录当前进行的轮数
21     if (ti==s&&l) {                                  //如果回到开始说明连成了环
22         ans=min(ans,l);                                 //比较出最小的轮数并保存
23         return;                                         //退出深搜
24     }
25     if (!d[t[ti]]) {                                 //判断该结点是否被搜索过 
26         d[t[ti]]=1;                                  //标记,1意味着该结点已搜索过
27         dfs(t[ti],s,l+1);                             //继续深搜
28     }
29 } 
30 void rmove(int ti) {                                    //删除ti
31     d[ti]=-1;                                         //标记,-1意味着删除该结点
32     r[t[ti]]--;                                      //ti的下一个人的入度减一
33     if (!r[t[ti]]&&d[t[ti]]!=-1) rmove(t[ti]);         //如果ti的下一个人的入读变为0且这个人未被删除,那么也将这个人删除,即标记为-1 
34 }
35 int main() {
36     memset(d,0,sizeof(d));
37     memset(r,0,sizeof(r));                             //r[i]为第 i 个人的入度
38     int i;
39     read(n);                                         //快速读入n(不会的同学可以直接用cin) 
40     for (i=1; i<=n; i++) {
41         read(t[i]);                                     //快速读入到t数组中,记录第i个人的下一个人(结点)
42         r[t[i]]++;                                     //记录第t[i]个人的入度(即有多少个人会传给他信息)
43     }
44     for (i=1; i<=n; i++) {
45         if (!r[i]&&d[i]!=-1) rmove(i);                 //如果i的入度为0且还未被删除,则删除i
46     }
47     for (i=1; i<=n; i++)
48         if (!d[i]) dfs(i,i,0);                       //如果i还未搜过且未被删除,则从i开始搜索
49     printf("%d",ans);
50     return 0;
51 }

 

posted @ 2019-03-13 21:31  ◆◇dear丶妖孽╮ゞ  阅读(112)  评论(0编辑  收藏  举报
……
芋、头、sleepwalking、…