[HDOJ4612]Warm up(双连通分量,缩点,树直径)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HDOJ4612]Warm up(双连通分量,缩点,树直径)相关的知识,希望对你有一定的参考价值。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612
所有图论题都要往树上考虑
题意:给一张图,仅允许添加一条边,问能干掉的最多条桥有多少。
必须解决重边的问题,最后会说。
首先tarjan跑出所有的双连通分量和是桥的边还有桥的数量,这非常重要。接着缩点重新建图,然后两遍dfs找出两个在树上距离最远的点。我的想法就是把这条最长的链连成一个环,让它成为一个双连通分量,这样的效果是最好的。最后就是用桥的数量减去树直径再减一就得到了剩下的桥的数量了。求树直径的时候重用了dfn数组,不要以为是错的就好。
重边真的好烦人啊,我像处理离散化那样unique了一下,发现是不可行的。最终还是参考了bin神的方法,在边的结构体里加一个记号来标记这个边是不是重边,也就是出现重边的话,那这几条重边就不是桥啦。如果按照我之前的做法,重边会被删掉,所以桥的数量会增多,显然是不对的。
1 /* 2 ━━━━━┒ギリギリ♂ eye! 3 ┓┏┓┏┓┃キリキリ♂ mind! 4 ┛┗┛┗┛┃\○/ 5 ┓┏┓┏┓┃ / 6 ┛┗┛┗┛┃ノ) 7 ┓┏┓┏┓┃ 8 ┛┗┛┗┛┃ 9 ┓┏┓┏┓┃ 10 ┛┗┛┗┛┃ 11 ┓┏┓┏┓┃ 12 ┛┗┛┗┛┃ 13 ┓┏┓┏┓┃ 14 ┃┃┃┃┃┃ 15 ┻┻┻┻┻┻ 16 */ 17 #include <algorithm> 18 #include <iostream> 19 #include <iomanip> 20 #include <cstring> 21 #include <climits> 22 #include <complex> 23 #include <fstream> 24 #include <cassert> 25 #include <cstdio> 26 #include <bitset> 27 #include <vector> 28 #include <deque> 29 #include <queue> 30 #include <stack> 31 #include <ctime> 32 #include <set> 33 #include <map> 34 #include <cmath> 35 using namespace std; 36 #define fr first 37 #define sc second 38 #define cl clear 39 #define BUG puts("here!!!") 40 #define W(a) while(a--) 41 #define pb(a) push_back(a) 42 #define Rint(a) scanf("%d", &a) 43 #define Rll(a) scanf("%lld", &a) 44 #define Rs(a) scanf("%s", a) 45 #define Cin(a) cin >> a 46 #define FRead() freopen("in", "r", stdin) 47 #define FWrite() freopen("out", "w", stdout) 48 #define Rep(i, len) for(int i = 0; i < (len); i++) 49 #define For(i, a, len) for(int i = (a); i < (len); i++) 50 #define Cls(a) memset((a), 0, sizeof(a)) 51 #define Clr(a, x) memset((a), (x), sizeof(a)) 52 #define Full(a) memset((a), 0x7f7f, sizeof(a)) 53 #define lp p << 1 54 #define rp p << 1 | 1 55 #define pi 3.14159265359 56 #define RT return 57 typedef long long LL; 58 typedef long double LD; 59 typedef unsigned long long ULL; 60 typedef pair<int, int> pii; 61 typedef pair<string, int> psi; 62 typedef map<string, int> msi; 63 typedef vector<int> vi; 64 typedef vector<LL> vl; 65 typedef vector<vl> vvl; 66 typedef vector<bool> vb; 67 68 const int maxn = 200020; 69 const int maxm = 1500000; 70 71 typedef struct Edge { 72 int u, v; 73 int next; 74 bool cut, r; 75 Edge() { next = -1; cut = 0; } 76 }Edge; 77 78 typedef struct Tmp { 79 int u, v; 80 Tmp() {} 81 Tmp(int uu, int vv) : u(uu), v(vv) {} 82 bool operator==(Tmp p) { RT u == p.u && v == p.v; } 83 }Tmp; 84 85 int head[maxn], ecnt; 86 int n, m; 87 int bcnt, idx; 88 int dfn[maxn], low[maxn]; 89 int stk[maxn], top; 90 int belong[maxn]; 91 bool instk[maxn]; 92 Edge edge[maxm]; 93 Tmp tmp[maxm]; 94 vector<int> G[maxn]; 95 96 bool cmp(Tmp x, Tmp y) { 97 if(x.u == y.u) RT x.v < y.v; 98 RT x.u < y.u; 99 } 100 101 void init() { 102 memset(edge, 0, sizeof(edge)); 103 memset(head, -1, sizeof(head)); 104 memset(instk, 0, sizeof(instk)); 105 memset(dfn, 0, sizeof(dfn)); 106 memset(low, 0, sizeof(low)); 107 memset(belong, 0, sizeof(belong)); 108 ecnt = top = bcnt = idx = 0; 109 } 110 111 void adde(int uu, int vv, bool p) { 112 edge[ecnt].u = uu; 113 edge[ecnt].v = vv; 114 edge[ecnt].cut = 0; 115 edge[ecnt].r = p; 116 edge[ecnt].next = head[uu]; 117 head[uu] = ecnt++; 118 } 119 120 void tarjan(int u, int p, int r) { 121 int v = u; 122 dfn[u] = low[u] = ++idx; 123 stk[++top] = u; 124 instk[u] = 1; 125 for(int i = head[u]; ~i; i=edge[i].next) { 126 v = edge[i].v; 127 if(v == p && (!r)) continue; 128 // if(v == p) continue; 129 if(!dfn[v]) { 130 tarjan(v, u, edge[i].r); 131 low[u] = min(low[u], low[v]); 132 if(low[v] > dfn[u]) edge[i].cut = edge[i^1].cut = 1; 133 } 134 else if(instk[v]) low[u] = min(low[u], dfn[v]); 135 } 136 if(dfn[u] == low[u]) { 137 bcnt++; 138 do { 139 v = stk[top--]; 140 instk[v] = 0; 141 belong[v] = bcnt; 142 } while(v != u); 143 } 144 } 145 146 void dfs(int u) { 147 Rep(i, G[u].size()) { 148 int v = G[u][i]; 149 if(dfn[v] != -1) continue; 150 dfn[v] = max(dfn[v], dfn[u] + 1); 151 dfs(v); 152 } 153 } 154 155 inline bool scan_d(int &num) { 156 char in;bool IsN=false; 157 in=getchar(); 158 if(in==EOF) return false; 159 while(in!=‘-‘&&(in<‘0‘||in>‘9‘)) in=getchar(); 160 if(in==‘-‘){ IsN=true;num=0;} 161 else num=in-‘0‘; 162 while(in=getchar(),in>=‘0‘&&in<=‘9‘){ 163 num*=10,num+=in-‘0‘; 164 } 165 if(IsN) num=-num; 166 return true; 167 } 168 169 int main() { 170 // FRead(); 171 int u, v; 172 while(~scan_d(n) && ~scan_d(m) && n + m) { 173 init(); 174 Rep(i, n+10) G[i].cl(); 175 Rep(i, m) { 176 scan_d(u); scan_d(v); 177 if(u == v) continue; 178 if(u > v) swap(u, v); 179 tmp[i] = Tmp(u, v); 180 } 181 sort(tmp, tmp+m, cmp); 182 // m = unique(tmp, tmp+m) - tmp; 183 Rep(i, m) { 184 u = tmp[i].u; v = tmp[i].v; 185 if(i == 0 || (tmp[i].u != tmp[i-1].u || tmp[i].v != tmp[i-1].v)) { 186 if(i < m - 1 && (tmp[i].u == tmp[i+1].u && tmp[i].v == tmp[i+1].v)) { 187 adde(u, v, 1); adde(v, u, 1); 188 } 189 else { 190 adde(u, v, 0); adde(v, u, 0); 191 } 192 } 193 } 194 tarjan(1, 0, 0); 195 For(u, 1, n+1) { 196 for(int i = head[u]; ~i; i=edge[i].next) { 197 if(edge[i].cut) { 198 v = edge[i].v; 199 G[belong[u]].pb(belong[v]); 200 } 201 } 202 } 203 Clr(dfn, -1); dfn[1] = 0; 204 dfs(1); 205 int pos = 1; 206 For(i, 1, bcnt+1) if(dfn[i] > dfn[pos]) pos = i; 207 Clr(dfn, -1); dfn[pos] = 0; 208 dfs(pos); 209 int ret = 0; 210 Rep(i, bcnt+1) { 211 ret = max(ret, dfn[i]); 212 } 213 printf("%d\n", bcnt - ret - 1); 214 } 215 RT 0; 216 }
以上是关于[HDOJ4612]Warm up(双连通分量,缩点,树直径)的主要内容,如果未能解决你的问题,请参考以下文章