ZOJ_3795 Grouping(强连通分量 拓扑)
来源:互联网 发布:ibm医疗大数据 编辑:程序博客网 时间:2024/06/07 10:38
题目请点我
题解:
这是我的第一道强连通分量,虽然参考了别人的代码,还是很有收获。强连通分量的查找和处理是很多图论题目的第一步,所以还是很重要,这道题只是有向图的强连通处理。
这道题因为题目有讲每组关系都是不小于,那么如果出现环的话那只有一种情况,就是环上所有人都是相等的年龄,则这个环上所有的人的比较关系都是可以等价的,这就是为什么我们要先对强连通分量尽行缩点处理,将每一个强连通分量作为一个整体,之后再依据层次关系构造拓扑序,利用拓扑序找到最长的一条序列。
算法讲解
代码参考
测试数据:
4 4
1 2
2 3
3 4
4 15 3
1 2
2 3
3 49 9
5 4
4 1
1 3
3 2
2 1
1 6
6 7
7 8
8 95 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 300010using 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;}
0 0
- ZOJ_3795 Grouping(强连通分量 拓扑)
- 强连通分量,拓扑序
- 【图论】强连通分量和拓扑排序
- [BZOJ2330][SCOI2011][拓扑排序][强连通分量][Tarjan]Candy
- [模板]拓扑排序, 强连通分量分解SCC
- hdu4324 Triangle LOVE 拓扑排序或强连通分量
- 训练赛 Grouping(强连通分量缩点 + DAG求最长路)
- zoj3795 Grouping DP+强连通
- 收缩强连通分量
- 强连通分量
- POJ2181强连通分量
- 强连通分量模板
- POJ_2762_强连通分量
- 强连通分量
- 强连通分量
- 强连通分量
- 强连通分量
- 【强连通分量】传话
- C++算法之——常用算法总结
- 发外链难还是建站难www.lanilani.cn
- 58 css 改变input type=file样式 placeholder属性
- 6.23 Block封装post异步网路请求& AFNetworking第三方封装
- nginx tomcat集群配置实现无痛重启服务教程python语言版本
- ZOJ_3795 Grouping(强连通分量 拓扑)
- 3038(HDU)
- Ubuntu下修改DNS方法(重启后也保留)
- System.Data.SQLite数据库介绍
- 求二叉树深度(递归方式)
- Log4j 2用法
- 10 个你需要了解的 Linux 网络和监控命令
- swift入门第二章运算符、字符串
- Ajax 完整教程