poj2186(强连通分量)
思路:找出出度为0 的顶点,如果出度为0的顶点大于1,则解为零,否则解就是出度为零的顶点的连通分支数。
刚开始是没有理解这道题的,也是看了大神之后才理解的。
方法一:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<vector>
#include<stack>
using namespace std;
const int maxx=20005;
const int inf=0x3f3f3f3f;
int low[maxx];
int dfn[maxx];
int vis[maxx];
int flag[maxx];
int blong[maxx];//记录这个节点属于哪个强连通分量
int indegree[maxx];//记录入度
int outdegree[maxx];//记录出度
int index;
int tcost[maxx];
int root;
int num[maxx];
int ans;//记录强连通分量的个数
int n,m;
int head[maxx];
stack<int>s;
vector<int>G[maxx];
struct node{int u,v;int next;
}e[maxx];
void add(int u,int v,int i){e[i].u=u;e[i].v=v;e[i].next=head[u];head[u]=i;
}
void dfs(int u){index++;low[u]=dfn[u]=index;s.push(u);vis[u]=1;for(int i=0;i<G[u].size();i++){int v=G[u][i];if(dfn[v]==0){dfs(v);low[u]=min(low[u],low[v]);}else if(vis[v]==1){low[u]=min(low[u],dfn[v]);}}if(dfn[u]==low[u]){ans++;int v;do{v=s.top();s.pop();num[ans]++;blong[v]=ans;vis[v]=0;}while(u!=v);}
}
void init(){ans=0;memset(head,-1,sizeof(head));memset(flag,0,sizeof(flag));memset(num,0,sizeof(num));memset(vis,0,sizeof(vis));memset(low,0,sizeof(low));memset(dfn,0,sizeof(dfn));memset(blong,0,sizeof(blong));memset(indegree,0,sizeof(indegree));memset(outdegree,0,sizeof(outdegree));while(!s.empty())s.pop();for(int i=0;i<=n;i++){G[i].clear();}
}
int main(){while(scanf("%d %d",&n,&m)!=EOF){init();for(int i=1;i<=m;i++){int a,b;scanf("%d %d",&a,&b);G[a].push_back(b);}index=1;for(int i=1;i<=n;i++){if(dfn[i]==0){dfs(i);}}for(int i=1;i<=n;i++){for(int j=0;j<G[i].size();j++){int v=G[i][j];if(blong[i]!=blong[v]){outdegree[blong[i]]++;}}}int ans1=0;int loc=1;for(int i=1;i<=ans;i++){if(outdegree[i]==0){ans1++;loc=i;}}if(ans1!=1){cout<<0<<endl;}else{ans1=0;for(int i=1;i<=n;i++){if(outdegree[blong[i]]==0){ans1++; }}cout<<ans1<<endl;}}return 0;
}
Kosaraju算法:
算法思路:
步骤1:对正向图(原图)进行dfs
求解得到正向图中各节点的拓扑序并且存在数组vs
中。
步骤2:得到拓扑序之后,对反向图按照逆拓扑序进行rdfs
,每次rdfs
都得到一个强连通分量。
注意:在进行第一步的dfs
之后,将数组vis
清空。
注解:Map
数组记录正向图,rMap
数组记录反向图,flag
数组标记属于哪个连通分量,vis
数组标记访问情况,vs
数组记录拓扑序。
方法二:Kosaraju算法
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
const int maxx=20005;
const int inf=0x3f3f3f3f;
vector<int>Map[maxx],rMap[maxx],vs;
int vis[maxx];
int n,m;
int flag[maxx];
int sum[maxx];
int indegree[maxx];
int outdegree[maxx];
int ans;
void init(){ans=0;memset(sum,0,sizeof(sum));memset(indegree,0,sizeof(indegree));memset(outdegree,0,sizeof(outdegree));memset(vis,0,sizeof(vis));memset(flag,0,sizeof(flag));for(int i=0;i<=n;i++){rMap[i].clear();Map[i].clear();}vs.clear();
}
void dfs(int v){vis[v]=1;for(int i=0;i<Map[v].size();i++){int t=Map[v][i];if(vis[t]==0){dfs(t);}}vs.push_back(v);
}
void rdfs(int v,int k){vis[v]=1;flag[v]=k;//v代表属于k这个连通分量 sum[k]++;for(int i=0;i<rMap[v].size();i++){int t=rMap[v][i];if(vis[t]==0){rdfs(t,k);}}
}
void solve(){for(int i=1;i<=n;i++){if(vis[i]==0){dfs(i);}}memset(vis,0,sizeof(vis));for(int i=vs.size()-1;i>=0;i--){if(vis[vs[i]]==0){ans++;rdfs(vs[i],ans);}}
}
int main(){int count=1;while(scanf("%d %d",&n,&m)!=EOF){init();for(int i=1;i<=m;i++){int a,b;scanf("%d %d",&a,&b);Map[a].push_back(b);rMap[b].push_back(a);}solve();for(int i=1;i<=n;i++){for(int j=0;j<Map[i].size();j++){int t=Map[i][j];if(flag[t]!=flag[i]){outdegree[flag[i]]++;indegree[flag[t]]++;}}}int ans1=0;for(int i=1;i<=ans;i++){if(outdegree[i]==0){ans1++;}}if(ans1!=1){cout<<0<<endl;}else{ans1=0;for(int i=1;i<=n;i++){if(outdegree[flag[i]]==0){ans1++;}}cout<<ans1<<endl;}}return 0;
}
poj2186(强连通分量)相关推荐
- poj2186(强连通分量分解)
题目大概意思为有 N 头牛,有些牛认为有些牛是红人,该关系具有传递性,例如果牛A觉得牛B是红人,牛B认为牛C是红人,则牛A也会认为牛C是红人,求被其他所有牛认为是红人的牛的总数 假设被其他所有牛认为是 ...
- POJ2186——并查集+Tarjan算法求强连通分量
算法讨论:这题陷阱比较多.首先,被所有牛欢迎,这说明所有的牛都要在一个连通图中,也就是将所给的边看成无向边的时候,所有点要在一个连通图中.这个我们用并查集来实现就可以了.强连通分量的求法就很简单了,正 ...
- POJ2186 Popular Cows【Tarjan】【强连通分量】
题目连接: http://poj.org/problem?id=2186 题目大意: 每头奶牛都希望自己成为最欢迎的那头牛.给你N头牛,M个崇拜关系(A,B).意思是牛A 崇拜牛B.特别是,如果牛A崇 ...
- 有向图——强连通分量
有向图的强连通分量(strongly connected components) 在有向图G中,如果两个顶点vi,vj间(vi!=vj)有一条从vi到vj的路径,同时还有一条从vj到vi的路径(顶点相 ...
- 【C++】强连通分量
强连通分量 先来一题例题 题目大意 怎么做? 分析 结论 不要高兴得太早 怎么办呢? 定义 缩点法 原图构建新图 发现 新的结论 强连通分量算法 Kosaraju算法 Tarjan算法 例题:信息传递 ...
- 极小连通子图和极大连通子图_强连通分量与拓扑排序
前言 由于GacUI里面开始多处用上拓扑排序,我决定把之前瞎JB搞出来的算法换掉,换成个正式的.之前我自己弄了个写起来很简单的算法,然后每一处需要用到的地方我就重新做一遍.当然这样肯定也是不行的,我觉 ...
- Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)...
转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2194090a96bbed2db1351de8.html 基本概念: 1.割点:若删掉某点后,原连通图 ...
- HDU4635(强连通分量+Kosaraju算法)
题意:给出一个有向图,最多添加多少条边使这个图依然不是强连通图:当这个图是强连通图时,输出-1: 求解思路:强连通分量求解: 强连通图:在有向图中,任意节点除法都可以到达其余所有节点,则称为强连通图. ...
- poj3352(强连通分量)
题意:添加多少边才能使这个无向图为双连通分量. 注意:双连通分量适用于无向图:而强连通分量适用于有向图.但是这两个概念都是一样的. #include<iostream> #include& ...
最新文章
- Python错误:AttributeError: 'generator' object has no attribute 'next'解决办法
- 提权函数之RtlAdjustPrivilege()
- 鸿蒙系统正式版官方下载,华为鸿蒙os2.0系统app正式版
- NAB 2019见闻:CAE视频编码与QoE
- 【 .NET Core 3.0 】框架之二 || 后端项目搭建
- Python常见设计模式
- java manager 如何使用_java – Android:如何使用AlarmManager
- dao-service-servlet-jsp构建简易web通讯录(三层开发)知识点1
- docker之快速部署gogs git
- IQueryable和IEnumerable,IList的区别
- hadoop程序MapReduce之DataSort
- java中简单的删除添加修改_教你数据库简单实现添加,显示,修改,删除的方法
- 【Robot 学习1】 机器人平台搭建
- 西宁公交调度员招聘计算机题库,调度员考试题库.doc
- z变换解差分方程例题_Z变换及差分方程的求解
- 双拼输入法学习-搜狗方案-3
- 低碳节能智慧路灯杆解决方案
- PHP海补知识(6)-- nl2br/ucfirst/ucwords
- Ethercat 从站开发总结一:协议总结
- 解决华为云服务器没有公网Ip无法上网问题
热门文章
- Linux CENTOS7 Linux网络性能测试工具-iperf 安装过程以及示例!
- 链表问题5——反转部分单向链表
- 圆桌讨论:Cloud 2.0时代的工业互联网与智能制造
- 智在生活 自在慵懒 科沃斯机器人X京东大牌秒杀日主题展亮相无锡
- Zabbix安装配置(CentOS7.3)
- “安全即代码”:整合安全团队和DevOps团队
- checkstyle安装使用
- 奕新集团--RAC环境后续
- Postfix(一):CentOS 下安装postfix
- 小shell脚本---查找目录下面包含string的文件