2 4 0 3 2 1 2 1 3
4 2题意:给出n个点和m条边,问最少须添加多少个边,使得任意两点间能互通。给出的m条边是有向的。解题:先求出强连通分量kk个,并把每个强连通重新编号为1至kk。再计算出新点的入度数与出度数,最终须要添加的边数就是 入度数与出度数之间最大的数。#include<stdio.h> #include<iostream> #include<vector> using namespace std; vector<int>map[20005]; int stack[20005],top,f[20005]; int ind[20005],outd[20005]; int low[20005],dfn[20005],vist[20005],deep,qlt[20005],kk; void init(int n)//初始化 { for(int i=1; i<=n; i++) { map[i].clear(); f[i]=0; vist[i]=0; ind[i]=0; outd[i]=0; } top=0; deep=0; kk=0; } void dfs(int v)//求出每个强连通分量 { deep++; vist[v]=1; low[v]=dfn[v]=deep; stack[++top]=v; f[v]=1; int len=map[v].size(); for(int i=0; i<len; i++) { int u=map[v][i]; if(vist[u]==0){ dfs(u); low[v]=(low[v]<low[u])?low[v]:low[u]; } else if(f[u]) low[v]=(low[v]<dfn[u])?low[v]:dfn[u]; } if(low[v]==dfn[v]) { kk++; while(stack[top]!=v){ qlt[stack[top]]=kk;//一个强连通分量看成一个整体点kk,把每个强连通分量连续编号为1~kk f[stack[top--]]=0; } qlt[stack[top]]=kk;f[stack[top--]]=0; } } int main() { int t,n,m,v,u; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); init(n); while(m--) { scanf("%d%d",&v,&u); map[v].push_back(u); } for(int i=1; i<=n; i++) if(vist[i]==0) dfs(i); if(kk==1) { printf("0\n"); continue; } for( v=1; v<=n; v++) { int k=map[v].size(); for(int e=0; e<k; e++) { u=map[v][e]; if(qlt[u]==qlt[v])continue;//当从v出发到达u,而u与v在同一强连通内部点 ind[qlt[u]]=1; outd[qlt[v]]=1; } } int ink=0,outk=0; for(int j=1; j<=kk; j++)//新点编号 { if(ind[j]==0)ink++; if(outd[j]==0)outk++; } printf("%d\n",ink>outk?ink:outk); } }
hdu2767Proving Equivalences(强连通,缩点),布布扣,bubuko.com
hdu2767Proving Equivalences(强连通,缩点)
原文:http://blog.csdn.net/u010372095/article/details/25832095