标签:
4 4 1 2 1 3 1 4 2 3 0 0
0
题意:有N个点,M条边,加一条边,求割边最少(有重边,所有点在原图中都是连通的)。
割边:在原图中去掉该边,原图变得不连通,这样的边成为割边。
思路:先求无向图的连通分量,缩点形成一个生成树,可知树中所有边都为割边,采用贪
心的策略可知,再加一条边,最少的割边数为 ans = 所有割边数 - 数的直径 。
因为有的图上可能有重边,这样不好处理。我们记录每条边的标号(一条无向边拆成的两
条有向边标号相同)这样就能限制不走一样的边而能走重边!
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
using namespace std;
const int maxn=200010;
struct edge
{
int u,v;
edge() {}
edge(int uu,int vv):u(uu),v(vv) {}
} a[maxn*10];
int n,m,dfs_clock,cnt,index,id[maxn],S[maxn],low[maxn],dfn[maxn],belong[maxn],num[maxn];
vector <int> G[maxn],T[maxn];
stack <int> st;
bool mark[maxn],visited[maxn*10];
void initial()
{
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(num,0,sizeof(num));
memset(mark,0,sizeof(mark));
memset(belong,0,sizeof(belong));
memset(visited,0,sizeof(visited));
for(int i=0; i<maxn; i++)
{
T[i].clear();
G[i].clear();
}
while(!st.empty()) st.pop();
index=0;
dfs_clock=1;
cnt=0;
}
void input()
{
int u,v;
for(int i=0; i<m; i++)
{
scanf("%d %d",&u,&v);
G[u].push_back(cnt);
a[cnt++]=edge(u,v);
G[v].push_back(cnt);
a[cnt++]=edge(v,u);
}
}
void tarjan(int u,int fa)
{
dfn[u]=low[u]=dfs_clock++;
st.push(u);
mark[u]=1;
for(int i=0; i<G[u].size(); i++)
{
int tp=G[u][i];
if(visited[tp]) continue;
visited[tp]=visited[tp^1]=1;
int v=a[tp].v;
if(!dfn[v])
{
tarjan(v,tp);
low[u]=min(low[v],low[u]);
}
else if(mark[v]) low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
index++;
while(1)
{
int t=st.top();
st.pop();
belong[t]=index;
if(t==u) break;
}
}
}
void solve1()
{
for(int i=1; i<=n; i++)
if(!dfn[i])
tarjan(i,-1);
for(int i=0; i<cnt; i+=2)
{
int p=belong[a[i].u],q=belong[a[i].v];
if(p!=q)
{
T[p].push_back(q);
T[q].push_back(p);
}
}
}
void dfs(int u,int v,int depth)
{
num[v]=depth;
for(int i=0; i<T[v].size(); i++)
{
int vv=T[v][i];
if(vv==u) continue;
dfs(v,vv,depth+1);
}
}
void solve2()
{
int Max=-1,k=-1;
dfs(-1,1,0);
for(int i=1; i<=index; i++) if(Max<num[i]) Max=num[i],k=i;
memset(num,0,sizeof(num));
dfs(-1,k,0);
for(int i=1; i<=index; i++) Max=max(Max,num[i]);
printf("%d\n",index-1-Max);
}
int main()
{
while(scanf("%d %d",&n,&m)!=EOF)
{
if(n==0 && m==0) break;
initial();
input();
solve1();
solve2();
}
return 0;
}
hdu 4612 Warm up (带有重边的无向图Tarjan+树的直径)
标签:
原文地址:http://blog.csdn.net/u012596172/article/details/43085777