洛谷P2661 信息传递
类似tarjan 强连通 灌水
题意 求一个特殊的图的最小环 这个图 有一个性质 每个点只有一条出边
这样满足一个性质,一张图只有 一个环,以及别的连向他们的边都是一些连向 或者 间接连向这个环的树枝
这些树枝一定不会连成环,因为 每个点只有一条出边,而不可能有两条,所以只要把这些树枝边都删掉,然后再
类似tarjan一样跑一遍灌水就行了
先说一下思路,这整道题就是给你几个带枝叶的环要你求最短环而已,于是在输入的时候可以把图中每个点的入度记录下来,然后再删除那些入度为0的点,因为这些点不能勾成环,另外,当删除这个点后如果其对应的下一个点入度为0这继续递归进行删除,在这之后,就直接用dfs求每个环的长度,求最小值即可,这里的dfs我用到了“时间戳”这个概念。
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <cstdlib> 5 #include <string> 6 #include <algorithm> 7 #include <iomanip> 8 #include <iostream> 9 using namespace std ; 10 11 inline int read() 12 { 13 char ch = getchar() ; 14 int f = 1,x = 0 ; 15 while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) f = -1 ; ch = getchar() ; } 16 while(ch>=‘0‘&&ch<=‘9‘) { x = x*10+ch-48 ; ch = getchar() ; } 17 return x * f ; 18 } 19 20 const int maxn = 200011 ; 21 int n,root,ans,ti,tmp,tot ; 22 int e[maxn],into[maxn],in[maxn] ; 23 bool vis[maxn] ; 24 25 inline void del(int u) 26 { 27 int v = e[ u ] ; 28 e[ u ] = 0 ; 29 in[ v ]--; 30 if(!in[ v ]) del(v) ; 31 } 32 33 inline void dfs(int u) 34 { 35 vis[ u ] = 1 ; 36 into[ u ] = ++ti ; 37 int v = e[ u ] ; 38 if(vis[ v ]==1) 39 { 40 tmp = into[ u ] - into[ v ]+1 ; 41 if(tmp<ans) ans = tmp ; 42 } 43 else dfs( v ) ; 44 45 } 46 47 int main() 48 { 49 n = read() ; 50 for(int i=1;i<=n;i++) e[ i ] = read(),in[e[ i ]]++ ; 51 ans = 1e9 ; 52 for(int i=1;i<=n;i++) 53 if(!in[ i ]) del( i ) ; 54 for(int i=1;i<=n;i++) 55 if(!vis[ i ] && in[ i ] ) 56 { 57 //for(int j=1;j<=n;j++) vis[ j ] = 0 ; 58 dfs( i ) ; 59 } 60 printf("%d\n",ans) ; 61 62 return 0 ; 63 }
时间: 2024-10-04 11:21:57