ZOJ_3795 Grouping(强连通分量 拓扑)
2015-06-23 19:36
357 查看
题目请点我
题解:
这是我的第一道强连通分量,虽然参考了别人的代码,还是很有收获。强连通分量的查找和处理是很多图论题目的第一步,所以还是很重要,这道题只是有向图的强连通处理。
这道题因为题目有讲每组关系都是不小于,那么如果出现环的话那只有一种情况,就是环上所有人都是相等的年龄,则这个环上所有的人的比较关系都是可以等价的,这就是为什么我们要先对强连通分量尽行缩点处理,将每一个强连通分量作为一个整体,之后再依据层次关系构造拓扑序,利用拓扑序找到最长的一条序列。
算法讲解
代码参考
测试数据:
4 4
1 2
2 3
3 4
4 1
5 3
1 2
2 3
3 4
9 9
5 4
4 1
1 3
3 2
2 1
1 6
6 7
7 8
8 9
5 5
1 2
2 3
3 4
4 1
5 1
代码实现:
题解:
这是我的第一道强连通分量,虽然参考了别人的代码,还是很有收获。强连通分量的查找和处理是很多图论题目的第一步,所以还是很重要,这道题只是有向图的强连通处理。
这道题因为题目有讲每组关系都是不小于,那么如果出现环的话那只有一种情况,就是环上所有人都是相等的年龄,则这个环上所有的人的比较关系都是可以等价的,这就是为什么我们要先对强连通分量尽行缩点处理,将每一个强连通分量作为一个整体,之后再依据层次关系构造拓扑序,利用拓扑序找到最长的一条序列。
算法讲解
代码参考
测试数据:
4 4
1 2
2 3
3 4
4 1
5 3
1 2
2 3
3 4
9 9
5 4
4 1
1 3
3 2
2 1
1 6
6 7
7 8
8 9
5 5
1 2
2 3
3 4
4 1
5 1
代码实现:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <limits.h> #include <queue> #define MAX_N 100010 #define MAX_M 300010 using namespace std; struct E{ int from,to,next; bool sign; }; int N,M; int result; int edgenum;//边的数目 int top,cnt,Time;//栈顶,强联通分量数目,时间轴 E edge[MAX_M];//边集 int dis[MAX_N];//拓扑序中节点的权值 int head[MAX_N];//前向星存储head数组 int belong[MAX_N];//记录某个点属于哪一个强连通分量 int indegree[MAX_N];//记录拓扑序中强连通分量入度 bool instack[MAX_N];//节点是否入栈 int DFN[MAX_N];//节点u搜索的次序编号(时间戳) int Low[MAX_N];//节点u或u的子树能追溯到的最早的栈中节点的次序号 int Stack[MAX_N];//手写栈 vector<int> G[MAX_N];//存储拓扑序 vector<int> bcnt[MAX_N];//存储每一个强连通分量 void add(int u,int v);//前向星加边 void tarjan(int u);//查找强连通分量 void tarjan_ini(int all); void suodian();//缩点函数,按照每个强连通分量构造拓扑序 int bfs(); int main(){ //freopen("in.txt","r",stdin); while( scanf("%d%d",&N,&M) != EOF ){ int a,b; edgenum = 0; memset(head,-1,sizeof(head)); while( M-- ){ scanf("%d%d",&a,&b); add(a,b); } tarjan_ini(N); suodian(); result = bfs(); printf("%d\n",result); } return 0; } void tarjan_ini(int all){ memset(DFN,-1,sizeof(DFN)); //初始化三个指针 top = Time = cnt = 0; for( int i = 1; i <= all; i++ ){ //查找每一个未被遍历的点的强连通分量 if( DFN[i] == -1 ){ tarjan(i); } } } //递归查找强连通分量 void tarjan(int u){ //标记时间戳 DFN[u] = Low[u] = ++Time; //入栈,注意这里的前++ Stack[++top] = u; instack[u] = true; //查找所有与u相邻边,寻找强连通分量 for( int i = head[u]; i != -1; i = edge[i].next ){ E tmp = edge[i]; //未被访问节点 if( DFN[tmp.to] == -1 ){ tarjan(tmp.to); //u或u的子树所能追溯到的最早的栈中节点 Low[u] = min(Low[u],Low[tmp.to]); } //已被访问且仍在栈中节点 else if( instack[tmp.to] ){ Low[u] = min(Low[u],DFN[tmp.to]); } } //u为强连通分量节点,弹栈,所有元素存储到一个vector数组 if( DFN[u] == Low[u] ){ int now; cnt++; bcnt[cnt].clear(); do{ //弹栈,注意这里的后-- now = Stack[top--]; //标记属于哪一个强连通分量 belong[now] = cnt; instack[now] = false; bcnt[cnt].push_back(now); }while( now != u );//弹到根节点截止 } } void suodian(){ for( int i = 1; i <= cnt; i++ ){ G[i].clear(); indegree[i] = 0; } //利用所有不在某一个强连通分量内部的边构造拓扑序 for( int i = 0; i < edgenum; i++ ){ int u,v; u = belong[edge[i].from]; v = belong[edge[i].to]; if( u != v ){ indegree[v]++; G[u].push_back(v); } } } void add(int u,int v){ E tmp = {u,v,head[u],false}; edge[edgenum] = tmp; head[u] = edgenum++; } int bfs(){ int tmp; queue<int> Q; for( int i = 1; i <= cnt; i++ ){ if( indegree[i] == 0 ){ Q.push(i); //初始权值为强连通分量的size dis[i] = bcnt[i].size(); } else{ dis[i] = 0; } } while( !Q.empty() ){ int u = Q.front(); Q.pop(); int len = G[u].size(); for( int i = 0; i < len; i++ ){ int v = G[u][i]; //叠加找到最大权值 dis[v] = max(dis[v],(int)bcnt[v].size()+dis[u]); //若该图为一个强连通图,不会进入这里更新 //tmp = max(tmp,dis[v]); indegree[v]--; if( indegree[v] == 0 ){ Q.push(v); } } } //得到结果 tmp = 1; for( int i = 1; i <= cnt; i++ ){ tmp = max(tmp,dis[i]); } return tmp; }
相关文章推荐
- hdu1827&&hdu2767----Kosaraju算法
- hdu3072&&hdu3639----Kosaraju算法
- [BZOJ1797][AHOI2009][最大流][强连通分量]Mincut最小割
- [BZOJ2330][SCOI2011][拓扑排序][强连通分量][Tarjan]Candy
- MZ Training 2014 #4 C题
- 图论算法(6) --- Tarjan算法求强连通分量
- 图论算法(6)(更新版) --- Tarjan算法求强连通分量
- POJ3114 Country in Wars Tarjan+Dij
- tarjan算法原理介绍
- 【算法学习】强连通分量
- HDU 1269 迷宫城堡 强连通分量模板题
- ZOJ_1462 Team Them Up! 求完连通分量后,再进行背包,之后背包路径回溯
- POJ_3160_强连通向量+缩点+BFS
- 计科1111-1114班第五周讲义、课外作业(强连通分量、BFS,截止日期:2014年4月11日23点-周五晚,学委飞信通知同学)
- POJ 2762判断单联通(强连通缩点+拓扑排序)
- POJ 2553 The Bottom of a Graph (强连通分量)
- POJ 2186 Popular Cows (强连通分量)
- POJ 2375 Cow Ski Area (强连通分量)
- POJ 2762 Going from u to v or from v to u?(强连通分量+拓扑排序)
- POJ 1904 King's Quest (强连通分量)