题意:
给一个连通无向图..两点间可能有多条边...问加一条边后..桥最少能有多少个...
题解:
之前没写过tarjan求双联通分量的...练习赛的时候思路有点乱.再加上不断的爆栈..就搞不定了..
首先求双联通分量并缩点..如果题目能保证没有重边..做了无向图tarjan后每个点的low值就代表在哪个双连通分量里....但题目就是要绕一下..那么就先求出哪些边是桥..然后dfs染色..碰到桥不过去..就行..再将颜色相同的点缩成一个..做边....这时这个图就成了一颗树..题目是说加一条边后..要让桥最少..显然是要连接某两个度为1的点( 叶子节点或者说只有一个孩子的根节点)...链接这两点后..又出来一个双联通块..双联通块中的桥全部变成非桥..题目再次转化..求用双联通缩点后的树中的最长链..很典型的树形DP....
题目恶心的是会爆栈...真心不想手动写栈做dfs了...提供一种方法..再程序上方加入#pragma comment(linker,"/STACK:102400000,102400000") 用C++提交就行
Program:
#pragma comment(linker,"/STACK:102400000,102400000") //申请栈空间..用C++提交
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#define ll long long
#define eps 1e-5
#define oo 1000000007
#define pi acos(-1.0)
#define MAXN 200005
#define MAXM 2000005
using namespace std;
struct node
{
int x,y,id,next;
}line[MAXM];
int Lnum,_next[MAXN],dfn[MAXN],low[MAXN],DfsIndex,dp[MAXN],tp[MAXN],tpnum,MM;
bool used[MAXN],brige[MAXM];
void addline(int x,int y,int id)
{
line[++Lnum].next=_next[x],_next[x]=Lnum;
line[Lnum].x=x,line[Lnum].y=y;
line[Lnum].id=id;
}
void tarjan(int x,int id)
{
int y,k;
dfn[x]=low[x]=++DfsIndex;
for (k=_next[x];k;k=line[k].next)
{
if (line[k].id==id) continue;
y=line[k].y;
if (!dfn[y])
{
tarjan(y,line[k].id);
low[x]=min(low[x],low[y]);
if (dfn[x]<low[y]) brige[k]=true;
}else
low[x]=min(low[x],dfn[y]);
}
return;
}
void dfs0(int x)
{
int k;
tp[x]=tpnum;
for (k=_next[x];k;k=line[k].next)
if (!tp[line[k].y] && !brige[k])
dfs0(line[k].y);
}
void dfs(int x)
{
int y,k;
dp[x]=0;
used[x]=true;
for (k=_next[x];k;k=line[k].next)
{
y=line[k].y;
if (used[y]) continue;
dfs(y);
MM=max(MM,dp[x]+dp[y]+1);
dp[x]=max(dp[x],dp[y]+1);
}
return;
}
int main()
{
int N,M,i;
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
while (~scanf("%d%d",&N,&M) && ( N || M) )
{
Lnum=0;
memset(_next,0,sizeof(_next));
while (M--)
{
int x,y;
scanf("%d%d",&x,&y);
addline(x,y,M),addline(y,x,M);
}
memset(dfn,0,sizeof(dfn));
memset(brige,false,sizeof(brige));
DfsIndex=0;
tarjan(1,-1);
tpnum=0;
memset(tp,0,sizeof(tp));
for (i=1;i<=N;i++)
if (!tp[i])
{
tpnum++;
dfs0(i);
}
memset(_next,0,sizeof(_next));
int x,y,temp=Lnum;
Lnum=0;
for (i=1;i<=temp;i++)
{
x=tp[line[i].x],y=tp[line[i].y];
if (x==y) continue;
addline(x,y,0);
}
memset(used,false,sizeof(used));
MM=0;
dfs(1);
printf("%d\n",tpnum-1-MM);
}
return 0;
}