hdu4612-Warm up(边的双连通分量)

时间:2023-03-10 03:07:23
hdu4612-Warm up(边的双连通分量)

题意:有n个点,m条边,有重边。现在可以任意在图上添加一条边,求桥的最少数目。

题解:思路就是求出双连通分量之后缩点成为一棵树,然后求出树的直径,连接树的直径就能减少最多的桥。

难点在于:有!重!边!

像我这样习惯于无脑用模板的人来说。。。。头疼死了。。。。。。

既然有重边,dfs的时候就不要标记点,以边为标记,然后照常求分量就好了。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <bitset>
#include <cstdio>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <map>
#include <set>
#define pk(x) printf("x=%d\n", x)
using namespace std;
#define PI acos(-1.0)
#define EPS 1E-6
#define clr(x,c) memset(x,c,sizeof(x))
typedef long long ll;
typedef pair<int, int> PII; const int N = ;
const int M = ; struct Edge {
int from, to, next;
int cut;
} edge[M];
int cnt_edge;
int head[N];
void add_edge(int u, int v)
{
edge[cnt_edge].from = u;
edge[cnt_edge].to = v;
edge[cnt_edge].next = head[u];
edge[cnt_edge].cut = ;
head[u] = cnt_edge++;
} int dfn[N]; int idx;
int low[N];
int stk[N]; int top;
int kind[N]; int cnt;
bool in[N]; void tarjan(int u, int pre)
{
low[u] = dfn[u] = ++idx;
in[u] = true;
stk[++top] = u;
for (int i = head[u]; i != -; i = edge[i].next)
{
int v = edge[i].to;
if (i == pre) continue;
if (!dfn[v])
{
tarjan(v, i^);
low[u] = min(low[u], low[v]);
if (low[v] > dfn[u])
{
edge[i].cut = true;
edge[i ^ ].cut = true;
}
}
else low[u] = min(low[u], dfn[v]);
}
if (low[u] == dfn[u])
{
cnt++;
int v;
do {
v = stk[top--];
in[v] = false;
kind[v] = cnt;
} while (u != v);
}
} vector<int> G[N];
int ans, ansv; void dfs(int u, int fa, int d) {
if (ans < d) {
ans = d;
ansv = u;
}
for (unsigned i = ; i < G[u].size(); ++i) {
int v = G[u][i];
if (v == fa) continue;
dfs(v, u, d+);
}
} void init()
{
for (int i = ; i < N; ++i) G[i].clear();
memset(dfn, , sizeof dfn);
memset(head, -, sizeof head);
top = idx = cnt = cnt_edge = ;
}
int main()
{
int n, m;
while (~scanf("%d%d", &n, &m)) {
if (n + m == ) break;
init();
int u, v;
for (int i = ; i < m; ++i) {
scanf("%d%d", &u, &v);
add_edge(u, v);
add_edge(v, u);
}
tarjan(, -); int ret = ;
for (int i = ; i < cnt_edge; ++i) {
if (edge[i].cut) {
int u = edge[i].from;
int v = edge[i].to; if (u < v)
ret++;
G[ kind[u] ].push_back( kind[v] );
}
}
ans = ; ansv = ; dfs(, -, );
ans = ; dfs(ansv, -, );
printf("%d\n", ret-ans); }
return ;
}
/**
6 6
1 2 2 3 3 4 4 5 2 6 6 2 6 8
1 2 2 3 3 4 4 5 2 6 6 2 1 3 4 7 5 4
2 1 2 3 2 4 2 5 5 5
2 1 2 3 2 4 2 5 3 4 5 5
1 2 2 3 3 4 3 4 4 5 0
1
2
0
0
*/

======

wa:12次,tle:1次,mle:3次,ce:2次

一颗赛艇。。。