LOJ10098
USACO 2006 Jan. Gold
为了从F个草场中的一个走到另一个,贝茜和她的同伴们不得不路过一些她们讨厌的可怕的树。奶牛们已经厌倦了被迫走某一条路,所以她们想建一些新路,使每一对草场之间都会至少有两条相互分离的路径,这样她们就有多一些选择。
每对草场之间已经有至少一条路径,给出所有R条双向路的描述,每条路连接了两个不同的草场,请计算最少的新建道路的数量。
路径由若干道路首尾相连而成,两条路径相互分离,是指两条路径没有一条重合的道路,但是两条分离的路径上可以有一些相同的草场。
对于同一对草场之间,可能已经有两条不同的道路,你也可以在它们之间再建一条道路,作为另一条不同的道路。
输入格式
第一行输入两个整数F和R;
接下来R行,每行输入两个整数,表示两个草场,它们之间有一条道路。
输出格式
输出最少需要新建的道路数目。
样例
样例输入
7 7
1 2
2 3
3 4
2 5
4 5
5 6
5 7
样例输出
2
数据范围与提示
F<=5000,R<=10000
______________________________________________________________
tarjan算法求双联通分量,实际上和求强联通分量是一样的,只要把双向边的反边标记为不可用就可以了。
求出双联通分量,重新建图,统计每个分量的度,叶子节点相互连接就可以了,所以答案就是(叶子数+1)/2
______________________________________________________________
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=5e3+10; 4 const int maxm=2e4+10; 5 int n,m; 6 struct edge 7 { 8 int u,v,nxt; 9 bool pd; 10 }e[maxm]; 11 int head[maxn],js; 12 void addage(int u,int v) 13 { 14 e[++js].u=u;e[js].v=v; 15 e[js].nxt=head[u];head[u]=js; 16 } 17 int low[maxn],dfn[maxn],cnt,st[maxn],top,lt[maxn],lts; 18 void tarjan(int u) 19 { 20 low[u]=dfn[u]=++cnt; 21 st[++top]=u; 22 for(int i=head[u];i;i=e[i].nxt) 23 if(e[i].pd==0) 24 { 25 e[(i&1)?i+1:i-1].pd=1; 26 int v=e[i].v; 27 if(!dfn[v]) 28 { 29 tarjan(v); 30 low[u]=min(low[u],low[v]); 31 } 32 else low[u]=min(low[u],dfn[v]); 33 34 } 35 if(low[u]==dfn[u]) 36 { 37 lt[u]=++lts; 38 while(st[top]!=u)lt[st[top--]]=lts; 39 --top; 40 } 41 } 42 int du[maxn]; 43 int main() 44 { 45 scanf("%d%d",&n,&m); 46 for(int u,v,i=1;i<=m;++i) 47 { 48 scanf("%d%d",&u,&v); 49 addage(u,v);addage(v,u); 50 } 51 tarjan(1); 52 for(int u=1;u<=n;++u) 53 for(int i=head[u];i;i=e[i].nxt) 54 { 55 int v=e[i].v; 56 if(lt[u]!=lt[v]) 57 { 58 du[lt[u]]++; 59 du[lt[v]]++; 60 } 61 } 62 int ans=0; 63 for(int i=1;i<=lts;++i) 64 if(du[i]==2)ans++; 65 cout<<((ans+1)>>1)<<endl; 66 return 0; 67 }