HDOJ--3836--Equivalent Sets(tarjan算法)//求连接几个SCC最少的边

原创 2015年11月21日 20:49:21

Equivalent Sets

Time Limit: 12000/4000 MS (Java/Others)    Memory Limit: 104857/104857 K (Java/Others)
Total Submission(s): 3621    Accepted Submission(s): 1264


Problem Description
To prove two sets A and B are equivalent, we can first prove A is a subset of B, and then prove B is a subset of A, so finally we got that these two sets are equivalent.
You are to prove N sets are equivalent, using the method above: in each step you can prove a set X is a subset of another set Y, and there are also some sets that are already proven to be subsets of some other sets.
Now you want to know the minimum steps needed to get the problem proved.
 

Input
The input file contains multiple test cases, in each case, the first line contains two integers N <= 20000 and M <= 50000.
Next M lines, each line contains two integers X, Y, means set X in a subset of set Y.
 

Output
For each case, output a single integer: the minimum steps needed.
 

Sample Input
4 0 3 2 1 2 1 3
 

Sample Output
4 2
Hint
Case 2: First prove set 2 is a subset of set 1 and then prove set 3 is a subset of set 1.
 
思路:利用tarjan算法求出SCC的数量,然后根据缩点后每个节点的入度出度情况来去求连接这几个SCC最少的边数。这里要利用到一个结论,连接几个SCC最少需要的边是缩点后几个节点的0入度数量和0出度数量中的最大值。详细见代码。
ac代码:
#include<stdio.h>
#include<string.h>
#include<stack>
#include<vector>
#include<algorithm>
#define INF 0x3f3f3f
#define MAXN 20000+10
using namespace std;
vector<int>mp[MAXN];//存储图 
vector<int>sccno[MAXN];//存储每个强连通分量;
vector<int>NEW[MAXN]; 
stack<int>q;//将遍历过得节点记录在栈里 
bool Instack[MAXN];//记录是否在栈里。 
int  In[MAXN],Out[MAXN];//记录入度,出度。	
int low[MAXN],dfn[MAXN],scc[MAXN];//sccno记录每个节点 属于哪个强连通分量 
int dfs_clock,scc_cnt; 
int n,m;
void get_map(){
	for(int i=1;i<=n;i++)
		mp[i].clear();
	for(int i=0;i<m;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		mp[u].push_back(v);
	}
}
void tarjan(int u){
	int v;//下一个节点; 
	low[u]=dfn[u]=++dfs_clock;
	Instack[u]=true;
	q.push(u); 
		for(int j=0;j<mp[u].size();j++){//遍历U节点的每一条边。 
					v=mp[u][j];
			if(!dfn[v]){
				tarjan(v);
				low[u]=min(low[u],low[v]);//更新low数组 
			}
			else	if(Instack[v])
				low[u]=min(low[u],dfn[v]);//建立反向边。
		} 	 
	if(dfn[u]==low[u]){
		scc_cnt++;
		while(1){
			v=q.top();
			q.pop();
			scc[v]=scc_cnt;
			sccno[scc_cnt].push_back(v); 
			Instack[v]=false;
			if(u==v)
				break;
		}
	} 
}
void find_cut(){
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(Instack,false,sizeof(Instack));
	dfs_clock=scc_cnt=0;
	for(int i=1;i<=n;i++)
		if(!dfn[i])
			tarjan(i);
}
void SCC(){
	memset(In,0,sizeof(In));
	memset(Out,0,sizeof(Out));
	for(int i=1;i<=scc_cnt;i++)
		NEW[i].clear();
	for(int i=1;i<=n;i++){
		for(int j=0;j<mp[i].size();j++){//遍历所有边,构建新图。
			 int u=scc[i];//找到这两个点是否是同一个强连通分量 
			 int v=scc[mp[i][j]];
			 if(u!=v) {//如果不是,构建新边。
			 NEW[u].push_back(v);
			 In[v]++;
			 Out[u]++; 
			 }	
		}
	}
}
void solve(){
	int sumin=0,sumout=0;
		if(scc_cnt==1){
			printf("0\n");
		}
		else{
			for(int i=1;i<=scc_cnt;i++){
				if(In[i]&&Out[i])
					continue;
				if(!In[i]) 
					sumin++;
				if(!Out[i])
					sumout++;
			}
				int ans=max(sumin,sumout);
				printf("%d\n",ans);
		}
}
int main(){
	while(scanf("%d%d",&n,&m)!=EOF){
		get_map();
		find_cut();
		SCC();
		solve(); 
	}
	
	return 0;
} 
自己终于算得上是稍微学会了一点强连通吧,也算是有点进步了。

版权声明:本文为小小呆原创文章,欲转载,请在后台勾搭本呆。

关于tarjan算法的一些理解(割点割边)

首先介绍以下tarjan算法: ---------------------------------------------tarjan算法------------------------------...
  • qq_24451605
  • qq_24451605
  • 2015年07月20日 06:44
  • 2066

tarjan算法(边的双连通分量)

hiho链接:http://hihocoder.com/contest/hiho53/problem/1 边的双连通分量定义:对于一个无向图的子图,当删除其中任意一条边后,不改变图内点的连通...
  • qwe2434127
  • qwe2434127
  • 2015年08月09日 18:05
  • 1292

求割点模板(tarjan算法思路)

想看更多模板,请点击:http://blog.csdn.net/martinue/article/category/6268283 贴上求割点模板: const int N=110; struct d...
  • martinue
  • martinue
  • 2016年05月04日 14:08
  • 1493

超详细Tarjan算法总结,求强连通分量,割点,割边,有重边的割边

Tarjan是一个人,他一身中发明了很多算法,就这几个算法最为出名。 1、求有向图的强连通分量,那么什么是强连通分量呢,就是一个顶点集合,任意两个顶点间都可以互相到达。如果图中任意两点可以互相到达,则...
  • lw277232240
  • lw277232240
  • 2017年06月14日 19:50
  • 365

求桥和割点的Tarjan算法

low[u]定义为u或者u的子树中能够通过非父子边追溯到的最早的节点的DFS开始时间 dfn[u]表示dfs下u的开始时间 割点:无向连通图中,如果删除某点后,图变成不连通,则称该点为割点。 桥...
  • qq_34446253
  • qq_34446253
  • 2016年08月22日 14:47
  • 634

tarjan模板(缩点,求有向图强连通分量)

整理出了这个tarjan模板,具体数组的功能代码都有注释。 const int N=100010; struct data { int to,next; } tu[N*2]; int head...
  • martinue
  • martinue
  • 2016年05月04日 15:53
  • 1515

强连通分量(SCC)Kosaraju算法学习笔记

一、深度优先生成树 在对无向图或有向图G进行从顶点v出发的深度优先搜索时,由v引向未被访问(标记)的顶点的边,构成以v为根的一棵树,这棵树被称为深度优先生成树(DFST)。 始点v称为树根、树上的每...
  • u014679804
  • u014679804
  • 2015年06月25日 18:06
  • 1252

tarjan算法解决LCA问题

昨天学习了tarjan算法解决LCA问题,今天来总结一下。首先,tarjan算法需要并查集的相关知识,你可以参考:并查集详解 (转)。然后可以简单应用并查集:并查集及其在最小生成树中的应用。并查集最主...
  • FreeeLinux
  • FreeeLinux
  • 2017年02月10日 21:01
  • 1273

Tarjan三大算法之双连通分量(双连通分量)

定义: 对于一个连通图,如果任意两点至少存在两条点不重复路径,则称这个图为点双连通的(简称双连通);如果任意两点至少存在两条边不重复路径,则称该图为边双连通的。点双连通图的定义等价于任意两条边都同在...
  • fuyukai
  • fuyukai
  • 2016年05月03日 16:18
  • 9097

Tarjan算法求解一个无向图中的割点和桥问题

基本概念割点:Articulation Point 在无向连通图中,删除一个顶点v及其相连的边后,原图从一个连通分量变成了两个或多个连通分量,则称顶点v为割点,同时也称关节点(Articulatio...
  • starstar1992
  • starstar1992
  • 2016年10月27日 13:29
  • 1442
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:HDOJ--3836--Equivalent Sets(tarjan算法)//求连接几个SCC最少的边
举报原因:
原因补充:

(最多只允许输入30个字)