hdu 4612 缩点 桥 树的直径

Posted pupil-xj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 4612 缩点 桥 树的直径相关的知识,希望对你有一定的参考价值。

// http://acm.hdu.edu.cn/showproblem.php?pid=4612

// 大致题意: 给n个点和m条边,组成一个无向连通图,问  给我加一条边的权力(可连接任意两点)->让图的桥数量最小,输出此时桥的数量。(2<=N<=200000, 1<=M<=1000000)

// 无向环里面的边没有桥,缩点,因为是连通图,所以缩完点后构成了一棵树,每条树边都是一个桥。要加一条边使得加完后图的桥数最小,结合上述,所以选择连接树直径的两端点。ans = 原先桥数 - 树的直径

树的直径两种写法:(参考  博客?? and 证明

树形dp 和 两次dfs(贪心思想)

dp :(代码短 但不能记录路径)

 1 void dp(int cur)
 2 {
 3     vis[cur] = true;             //当前结点已访问
 4     for(int i = head[cur]; i != -1; i = edge[i].nxt){
 5         int v = edge[i].v;
 6         if(vis[v]) continue;  //不走回头路
 7         dp(v);
 8         ans_max = max(ans_max, d[cur] + d[v] + edge[i].w); //更新树的直径(由当前结点两段之和更新)
 9         d[cur] = max(d[cur], d[v]+edge[i].w);                    //更新当前结点所能走的最长路径(保留较长的那边)
10     }
11 }

dfs:(代码长 但是可以记录路径)

 1 void dfs(int cur)
 2 {
 3     for(int i = head[cur]; i != -1; i = edge[i].nxt){
 4         int v = edge[i].v;
 5         if(fa[cur] == v) continue; //不走回头路,也可以递归父亲结点省去fa数组空间
 6         fa[v] = cur;
 7         dis[v] = dis[cur] + edge[i].w;  //当前结点最长路径
 8         dfs(v);
 9     }
10 }第一次dfs(任意点) dfs之后for循环找出最深度的点x 然后再dfs(x)

 // hdu 4612

  1 /*
  2  * @Promlem: 
  3  * @Time Limit: ms
  4  * @Memory Limit: k
  5  * @Author: pupil-XJ
  6  * @Date: 2019-10-31 23:41:06
  7  * @LastEditTime: 2019-11-01 00:57:51
  8  */
  9 #include<cstdio>
 10 #include<iostream>
 11 #include<algorithm>
 12 #include<stack>
 13 #define read(n) n = read_n()
 14 #define rep(i, n) for(int i=0;i!=n;++i)
 15 #define rep1(i, n) for(int i=1;i<=n;++i)
 16 #pragma comment(linker, "/STACK:102400000,102400000")
 17 using namespace std;
 18 
 19 inline int read_n() {
 20     char c=getchar();int x=0,f=1;
 21     while(c<0||c>9){if(c==-)f=-1;c=getchar();}
 22     while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
 23     return x*f;
 24 }
 25 // -----------------------------------------------------
 26 const int MAXN = 200000+5;
 27 const int MAXM = 2000000+5;
 28 
 29 int num;
 30 int head[MAXN];
 31 struct node {
 32     int v, next;
 33 } edge[MAXM];
 34 
 35 inline void add(int x, int y) {
 36     edge[num].v = y;
 37     edge[num].next = head[x];
 38     head[x] = num++;
 39 }
 40 // 上面图结构体 下面树结构体
 41 int numt;
 42 int headt[MAXN];
 43 struct t {
 44     int v, next;
 45 } tree[MAXM];
 46 
 47 inline void addt(int x, int y) {// 加树边
 48     tree[numt].v = y;
 49     tree[numt].next = headt[x];
 50     headt[x] = numt++;
 51 }
 52 
 53 int n, m;
 54 int cnt, scc;
 55 int dfn[MAXN], low[MAXN], sccno[MAXN];
 56 bool vis[MAXN];
 57 stack<int> st;
 58 
 59 void Tarjan(int cur, int edge_num) {// 缩点
 60     dfn[cur] = low[cur] = ++cnt;
 61     vis[cur] = true;
 62     st.push(cur);
 63     for(int i = head[cur]; i != -1; i = edge[i].next) {
 64         if(edge_num != -1 && i == (edge_num^1)) continue;
 65         int v = edge[i].v;
 66         if(!dfn[v]) {
 67             Tarjan(v, i);
 68             low[cur] = min(low[cur], low[v]);
 69         }
 70         else if(vis[v]) low[cur] = min(low[cur], dfn[v]);
 71     }
 72     if(dfn[cur] == low[cur]) {
 73         ++scc;
 74         int v;
 75         do {
 76             v = st.top();
 77             st.pop();
 78             vis[v] = false;
 79             sccno[v] = scc;
 80         } while(v != cur);
 81     }
 82 }
 83 
 84 int ans;
 85 int dis[MAXN];
 86 
 87 void build() {// 建树
 88     numt = 0;
 89     rep1(u, n) {
 90         for(int i = head[u]; i != -1; i = edge[i].next) {
 91             int v = edge[i].v;
 92             if(sccno[u] != sccno[v]) {
 93                 addt(sccno[u], sccno[v]);
 94                 addt(sccno[v], sccno[u]);
 95             }
 96         }
 97     }
 98 }
 99 
100 void dp(int cur) {// 求直径
101     vis[cur] = true;
102     for(int i = headt[cur]; i != -1; i = tree[i].next) {
103         int v = tree[i].v;
104         if(vis[v]) continue;
105         dp(v);
106         ans = max(ans, dis[cur] + dis[v] + 1);
107         dis[cur] = max(dis[cur], dis[v] + 1);
108     }
109 }
110 
111 void solve() {
112     cnt = scc = 0;
113     rep1(i, n) dfn[i] = 0, vis[i] = false, headt[i] = -1;
114     Tarjan(1, -1);
115     build();
116     rep1(i, scc) vis[i] = false, dis[i] = 0;
117     ans = 0;
118     dp(1);
119     cout << scc-1-ans << "
";
120 }
121 
122 int main() {
123     while(scanf("%d%d", &n, &m) == 2 && n) {
124         num = 0;
125         rep1(i, n) head[i] = -1;
126         int x, y;
127         rep(i, m) {
128             read(x); read(y);
129             add(x, y); add(y, x);
130         }
131         solve();
132     }
133     return 0;
134 }

 

以上是关于hdu 4612 缩点 桥 树的直径的主要内容,如果未能解决你的问题,请参考以下文章

HDU 4612 Warm up

HDU4612 Warm up

HDU4612:Warm up(缩点+树的直径)

HDU 4612 Warm up(双连通分量缩点+求树的直径)

HDU 4612 Warm up —— (缩点 + 求树的直径)

HDOJ4612双连通分量缩点+找树的直径