题意:给出一个无向图,可能包含重边和自环,现在可以在这个图上加上一条边,问加完这条边后图上最少有多少桥边。
思路:首先求出所有边双连通分量,然后缩点,缩点以后形成了一棵树,那么只要我们将树上最长的一条链变成一个环,那么肯定可以减少最多的桥边,问题就变成了求出边双连通分量,这道题一开始一直wa,因为没考虑清楚重边的影响,将tarjan里的判断当前点是否是父亲结点改成判断当前边是否是从父亲结点连过来的边,那么我们只需要对所有边编号即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 200100;//点数
const int MAXM = 2000100;//边数
int n, m;
struct Edge
{
int from, to, next, id;
bool cut;//是否是桥标记
}edge[MAXM];
int head[MAXN], tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];//Belong数组的值是1~Block
int Index, Top;
int Block;//边双连通块数
bool Instack[MAXN];
vector<int> G[MAXN]; //所点后形成的图
void addedge(int u,int v,int i)
{
edge[tot].from = u;edge[tot].to = v;edge[tot].next = head[u];edge[tot].cut=false;edge[tot].id = i;
head[u] = tot++;
}
void init()
{
memset(head,-1,sizeof(head));
memset(DFN,0,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
Index = Top = Block = tot = 0;
for(int i = 1; i <= n; i++) G[i].clear();
}
void Tarjan(int u,int id)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[Top++] = u;
Instack[u] = true;
for(int i = head[u];i != -1;i = edge[i].next)
{
v = edge[i].to;
if(edge[i].id == id) continue;
if( !DFN[v] )
{
Tarjan(v, edge[i].id);
if( Low[u] > Low[v] )Low[u] = Low[v];
}
else if( Instack[v] && Low[u] > DFN[v] )
Low[u] = DFN[v];
}
if(Low[u] == DFN[u])
{
Block++;
do
{
v = Stack[--Top];
Instack[v] = false;
Belong[v] = Block;
}
while( v!=u );
}
}
void suodian() {
for(int i = 1; i <= n; i++) {
for(int e = head[i]; e != -1; e = edge[e].next) {
int u = edge[e].to;
if(Belong[u] != Belong[i]) G[Belong[i]].push_back(Belong[u]);
}
}
}
bool vis[MAXN];
int dist[MAXN];
int bfs(int cur) {
memset(vis, 0, sizeof(vis));
queue<int> q;
q.push(cur);
vis[cur] = 1;
dist[cur] = 0;
int t;
while(!q.empty()) {
t = q.front(); q.pop();
for(int i = 0; i < G[t].size(); i++) {
int u = G[t][i];
if(vis[u]) continue;
dist[u] = dist[t] + 1;
vis[u] = 1;
q.push(u);
}
}
return t;
}
int main() {
//freopen("input.txt", "r", stdin);
while(scanf("%d%d", &n, &m)==2 && n) {
init();
for(int i = 1; i <= m; i++) {
int u, v; scanf("%d%d", &u, &v);
if(u == v) continue;
addedge(u, v, i);
addedge(v, u, i);
}
Tarjan(1, -1);
suodian();
int maxlen = dist[bfs(bfs(1))];
cout << Block-1-maxlen << endl;
}
return 0;
}