HDU 2767 Proving Equivalences(强连通分量)
2015-08-31 10:14
585 查看
Description
给一张有向图,要求添加最少的边使这张图变成连通图
Input
第一行为用例组数T,每组用例第一行为两个整数n和m表示点数和边数,之后m行每行两个整数a和b表示a到b有一条有向边
Output
对于每组用例,输出使得这张图变成连通图所需添加的最少边数
Sample Input
2
4 0
3 2
1 2
1 3
Sample Output
4
2
Solution
首先用tarjan算法求强连通分量缩点后将这张图变成DAG,显然让一个有向无环图变成连通图所需的最少边数为max(出度为0的点数,入度为0的点数),至于怎么统计出入度为0的点(缩点后的点,每个点都是一个连通块),我们可以枚举每条边,只要这条边的起点和终点不处于同一个连通块中,那么起点所处的连通块出度加一,终点所处的连通块入度加一即可
Code
给一张有向图,要求添加最少的边使这张图变成连通图
Input
第一行为用例组数T,每组用例第一行为两个整数n和m表示点数和边数,之后m行每行两个整数a和b表示a到b有一条有向边
Output
对于每组用例,输出使得这张图变成连通图所需添加的最少边数
Sample Input
2
4 0
3 2
1 2
1 3
Sample Output
4
2
Solution
首先用tarjan算法求强连通分量缩点后将这张图变成DAG,显然让一个有向无环图变成连通图所需的最少边数为max(出度为0的点数,入度为0的点数),至于怎么统计出入度为0的点(缩点后的点,每个点都是一个连通块),我们可以枚举每条边,只要这条边的起点和终点不处于同一个连通块中,那么起点所处的连通块出度加一,终点所处的连通块入度加一即可
Code
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<algorithm> #include<stack> #include<vector> using namespace std; #define maxn 22222 vector<int>g[maxn]; stack<int>st; int n,m,scc,index; int low[maxn],dfn[maxn],instack[maxn],fa[maxn]; void init()//初始化 { scc=index=0; while(!st.empty())st.pop(); for(int i=0;i<maxn;i++)g[i].clear(); memset(dfn,0,sizeof(dfn)); memset(instack,0,sizeof(instack)); memset(low,0,sizeof(low)); } void tarjan(int u)//求强联通分量 { dfn[u]=low[u]=++index; instack[u]=1; st.push(u); int v,size=g[u].size(); for(int i=0;i<size;i++) { v=g[u][i]; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(instack[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { scc++; do { v=st.top(); st.pop(); fa[v]=scc; instack[v]=0; }while(v!=u); } } int main() { int t; scanf("%d",&t); while(t--) { init(); scanf("%d%d",&n,&m); for(int i=0;i<m;i++) { int u,v; scanf("%d%d",&u,&v); g[u-1].push_back(v-1); } for(int i=0;i<n;i++) if(!dfn[i]) tarjan(i); if(scc==0)//每个点分别是一个连通块则需要连n条边 { printf("%d\n",n); continue; } if(scc==1)//所有点互相连通处于同一个连通块中则不需要多建边 { printf("0\n"); continue; } int cnt1[maxn];//出度 int cnt2[maxn];//入度 //初始化 memset(cnt1,0,sizeof(cnt1)); memset(cnt2,0,sizeof(cnt2)); for(int i=0;i<n;i++) for(int j=0;j<g[i].size();j++) { int v=g[i][j]; if(fa[i]!=fa[v])//两点不在同一个连通块中 { cnt1[fa[i]]++;//边的起点所处的连通块出度加一 cnt2[fa[v]]++;//边的终点所处的连通块入度加一 } } int ans1=0; int ans2=0; for(int i=1;i<=scc;i++)//分别统计出入度为0的连通块的数量 { if(!cnt1[i])ans1++; if(!cnt2[i])ans2++; } printf("%d\n",max(ans1,ans2)); } return 0; }
相关文章推荐
- NSURLConnection和UITableView的delegate执行先后问题的解决方法
- Android中AsyncTask类与AsyncQueryHandler类的用法
- 7.Builder Pattern的学习和使用
- ArcGIS for Android示例解析之空间查询-----QueryTask
- UVA 1152 4 Values whose Sum is 0
- Assertion failure in -[UIView layoutSublayersOfLayer:]
- 叶孤城:UICollectionView自定义布局教程——Pinterest
- 问题:ExecuteNonQuery 与 ExecuteScalar 结果: ExecuteNonQuery方法和ExecuteScalar方法的区别
- UI:转自互联网资料
- interface builder的身世
- UI 19 数据库的练习
- iOS(总结)UIPickerView&&UIDatePicker&&toolBar
- POJ 3589 Number-guessing Game(水~)
- Memo Mirantis Fuel 6.1的Internet连接
- 【翻译自mos文章】当sec_case_sensitive_logon = true后,怎么启用大小写混合的密码?
- iOS-按钮(UIButton)不能和用户交互的五种情况
- 黑马程序员——GUI——GUI概述与使用
- UVALive - 3972 March of the Penguins(最大流+枚举)
- UVALive - 2531 The K-League(最大流+枚举)
- Ueditor+MVC