uva11324 有向无环图求直径

本文介绍使用Tarjan算法进行缩点处理,将原图转换为有向无环图,并通过深度优先搜索求解各个节点作为起点时的最长路径,最终找出整个图的最大直径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  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. }  
### UVa818 切断圆环链问题解决方案 对于UVa818切断圆环链的问题,目标是在最少切割次数的情况下将给定长度的闭合链条分割成指定数量的小段。该问题可以通过贪心法来有效解。 #### 贪婪策略分析 为了最小化切割次数,在每次操作时应尽可能多地利用已有的切口位置。具体来说,当需要制作n个链接时,只需要做(n-1)次切割即可完成任务[^1]。 #### 实现方法概述 程序接收一系列整数作为输入数据,表示所需制造的不同尺寸片段数目;接着计并输出达到这些要所需的最低切割次数。这里给出Python版本的具体实现: ```python def min_cuts_needed(links): """Calculate minimum cuts needed to produce given link counts.""" # Remove duplicates and sort descendingly unique_links = sorted(set(links), reverse=True) total_cuts, current_length = 0, 0 while unique_links: next_cut = unique_links.pop(0) if not unique_links or (unique_links[0]*2 >= next_cut): total_cuts += 1 current_length = next_cut elif sum(unique_links)*2 < next_cut: break else: temp_sum = 0 index_to_remove = None for i, val in enumerate(unique_links): temp_sum += val if temp_sum*2 >= next_cut: index_to_remove = i break del unique_links[:index_to_remove+1] total_cuts += 1 current_length = next_cut return max(total_cuts - 1, 0) if __name__ == "__main__": import sys input_data = list(map(int, sys.stdin.readline().strip().split())) result = min_cuts_needed(input_data[:-1]) print(result) ``` 此代码实现了上述贪婪策略,并通过标准输入读取测试案例中的链接需列表。注意最后会减去一次因为初始状态下的虚拟“零”切片[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值