hdu 1269+hdu 2767(强连通分量)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1269
View Code
1 #include<iostream> 2 #include<vector> 3 #include<stack> 4 const int MAXN=10000+10; 5 using namespace std; 6 vector<int>mp[MAXN]; 7 stack<int>S; 8 int n,m; 9 int _count; 10 int cnt; 11 bool mark[MAXN]; 12 int dfn[MAXN]; 13 int low[MAXN]; 14 15 //求强连通分量tarjan 16 void Tarjan(int u){ 17 dfn[u]=low[u]=++cnt; 18 mark[u]=true; 19 S.push(u); 20 for(int i=0;i<mp[u].size();i++){ 21 int v=mp[u][i]; 22 if(dfn[v]==0){ 23 Tarjan(v); 24 low[u]=min(low[u],low[v]); 25 }else if(mark[v]&&dfn[v]<low[u]){ 26 low[u]=dfn[v]; 27 } 28 } 29 if(low[u]==dfn[u]){ 30 _count++; 31 int v; 32 do{ 33 v=S.top(); 34 S.pop(); 35 mark[v]=false; 36 }while(u!=v); 37 } 38 } 39 40 41 int main(){ 42 while(~scanf("%d%d",&n,&m)){ 43 if(n==0&&m==0)break; 44 for(int i=1;i<=n;i++)mp[i].clear(); 45 for(int i=1;i<=m;i++){ 46 int x,y; 47 scanf("%d%d",&x,&y); 48 mp[x].push_back(y); 49 } 50 memset(mark,false,sizeof(mark)); 51 memset(dfn,0,sizeof(dfn)); 52 memset(low,0,sizeof(low)); 53 _count=0; 54 cnt=0; 55 for(int i=1;i<=n;i++){ 56 if(dfn[i]==0){ 57 Tarjan(i); 58 } 59 } 60 if(_count>1){ 61 printf("No\n"); 62 }else 63 printf("Yes\n"); 64 } 65 return 0; 66 }
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2767
思路:可以用tarjan算法求出求出有向图的强连通分量,并进行染色,然后在缩点,缩点的好处就是把原本杂乱的有向图变成有向无环图。。。
然后统计入度为0的点和出度为0的点,取其较大值就是所求的要求添加的最少的边的条数了。
View Code
1 #include<iostream> 2 #include<vector> 3 #include<stack> 4 const int MAXN=20000+10; 5 using namespace std; 6 vector<int>mp[MAXN]; 7 stack<int>S; 8 bool mark[MAXN]; 9 int dfn[MAXN],low[MAXN]; 10 int color[MAXN];//染色 11 int n,m,_count,cnt; 12 int from[MAXN],to[MAXN]; 13 14 15 //求有向图强连通分量 16 void Tarjan(int u){ 17 dfn[u]=low[u]=++cnt; 18 mark[u]=true; 19 S.push(u); 20 for(int i=0;i<mp[u].size();i++){ 21 int v=mp[u][i]; 22 if(dfn[v]==0){ 23 Tarjan(v); 24 low[u]=min(low[u],low[v]); 25 }else if(mark[v]&&dfn[v]<low[u]){ 26 low[u]=dfn[v]; 27 } 28 } 29 if(low[u]==dfn[u]){ 30 _count++; 31 int v; 32 do{ 33 v=S.top(); 34 S.pop(); 35 mark[v]=false;//相当于出栈 36 color[v]=_count; //缩点,把一个杂乱无章的有向图变成一个有向无环图 37 }while(u!=v); 38 } 39 } 40 41 int main(){ 42 int _case; 43 scanf("%d",&_case); 44 while(_case--){ 45 scanf("%d%d",&n,&m); 46 for(int i=1;i<=n;i++)mp[i].clear(); 47 for(int i=1;i<=m;i++){ 48 int x,y; 49 scanf("%d%d",&x,&y); 50 mp[x].push_back(y); 51 } 52 memset(mark,false,sizeof(mark)); 53 memset(dfn,0,sizeof(dfn)); 54 memset(low,0,sizeof(low)); 55 memset(color,0,sizeof(color)); 56 memset(from,0,sizeof(from)); 57 memset(to,0,sizeof(to)); 58 _count=0,cnt=0; 59 for(int i=1;i<=n;i++){ 60 if(dfn[i]==0){ 61 Tarjan(i); 62 } 63 } 64 if(_count==1){ 65 printf("0\n"); 66 continue; 67 } 68 for(int i=1;i<=n;i++){ 69 for(int j=0;j<mp[i].size();j++){ 70 int k=mp[i][j]; 71 if(color[i]!=color[k]){ 72 from[color[i]]++;//标记color[]表示记录的是第几个连通分量 73 to[color[k]]++; 74 } 75 } 76 } 77 int in=0,out=0; 78 for(int i=1;i<=_count;i++){ 79 if(from[i]==0)out++;//出度为0 80 if(to[i]==0)in++;//入度为0 81 } 82 printf("%d\n",max(in,out));//max(in,out)即为最少需要连的边 83 } 84 return 0; 85 } 86 87 88 89 90 91 92 93
下面贴一个tarjan的算法流程:
tarjan(u)
{
dfn[u]=low[u]=++cnt;
Stack.push(u)
for(each(u,v) in E)
if(v is not visited)
tarjan(v);
low[u]=min(low[u],low[v]);
else if(v is in Stack)
low[u]=min(low[u],dfn[v]);
if(dfn[u]==low[u])
repeat
v=Stack.pop
print v
until(u==v);
}