uva11324 有向无环图求直径

  1. a到b,b到a,ab互相到达。这三个条件满足一个即可。那么我们先tarjan缩点,把ab互相到达的记录下来,让这个图变成一个有向无环图。
  2. 之后分别以各个点为起点,求最长直径即可。求出最大值来。



  1. #include <iostream>  
  2. #include <stack>  
  3. #include <vector>  
  4. #include <cstdio>  
  5. #include <cstring>  
  6. using namespace std;  
  7. const int maxn = 1e3 + 10;  
  8. int low[maxn],pre[maxn],sccno[maxn];  
  9. int scc_cnt,dfs_colok;  
  10. stack<int> s;  
  11. vector<int> G[maxn],mp[maxn];  
  12. void dfs(int u){  
  13.     low[u] = pre[u] = ++dfs_colok;  
  14.     s.push(u);  
  15.     for (int i = 0;i < G[u].size();++i){  
  16.         int v = G[u][i];  
  17.         if (!pre[v]){  
  18.             dfs(v);  
  19.             low[u] = min(low[v],low[u]);  
  20.         }else if (!sccno[v]) low[u] = min(low[u],pre[v]);  
  21.     }  
  22.     if (low[u] == pre[u]){  
  23.         scc_cnt++;  
  24.         for (;;){  
  25.             int x = s.top();  
  26.             s.pop();  
  27.             sccno[x] = scc_cnt;  
  28.             if (x == u) break;  
  29.         }  
  30.     }  
  31. }  
  32. void find_scc(int n){  
  33.     dfs_colok = scc_cnt = 0;  
  34.     memset(sccno, 0, sizeof sccno);  
  35.     memset(pre, 0,sizeof pre);  
  36.     for (int i = 0;i < n;i++)  
  37.         if (!pre[i]) dfs(i);  
  38. }  
  39. int val[maxn];  
  40. void build(int n){  
  41.     for (int i = 1;i <= scc_cnt;i++)  
  42.         mp[i].clear();  
  43.     memset(val, 0,sizeof val);  
  44.     for (int i = 0;i < n;i++){  
  45.         val[sccno[i]]++;  
  46.         // cout << val[sccno[i]] << endl;  
  47.     }  
  48.     for (int i = 0;i < n;i++){  
  49.         for (int j = 0;j < G[i].size();j++){  
  50.             int v = G[i][j];  
  51.             if (sccno[i] != sccno[v]){  
  52.                 mp[sccno[i]].push_back(sccno[v]);  
  53.             }  
  54.         }  
  55.     }  
  56. }  
  1. int dp[maxn];  
  2. int search(int u)  //求u为起点的长度
  3. {   
  4.     if (dp[u] != -1) return dp[u];  //如果u已经搜完了,直接返回u的长度    
  5.     dp[u] = val[u];      //u首先等于他自己的长度,也就是缩点时,他自身包含的点数
  6.     for (int i = 0;i < mp[u].size();i++){    //遍历所有的点
  7.         int v = mp[u][i];   //对于和u相连的点v
  8.         dp[u] = max(dp[u],search(v) + val[u]); //u的长度=max(他自身,v的长度+他自己的长度)  
  9.     }  
  10.     // cout << dp[u] << endl;  
  11.     return dp[u];  
  12. }  
  13. int main(){  
  14.     // freopen("in.txt","r",stdin);  
  15.     // freopen("out","w",stdout);  
  16.     int n,m,t;  
  17.     scanf("%d",&t);  
  18.     while(t--){  
  19.         scanf("%d%d",&n,&m);  
  20.         for (int i = 0;i < n;i++)  
  21.             G[i].clear();  
  22.         int a,b;  
  23.         for (int i = 1;i <= m;i++){  
  24.             scanf("%d%d",&a,&b);  
  25.             a--;  
  26.             b--;  
  27.             G[a].push_back(b);  
  28.         }  
  29.         find_scc(n);  
  30.         // cout << "scc_cnt = " << scc_cnt << endl;  
  31.         build(n);  
  32.         memset(dp, -1,sizeof dp);  
  33.         int ans = 0;  
  34.         // for (int i = 1;i <= scc_cnt;i++)  
  35.         for (int i = 0;i < n;i++)  
  36.             ans = max(ans,search(sccno[i]));  
  37.         printf("%d\n", ans);  
  38.     }  
  39.     return 0;  
  40. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值