落谷 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 }