POJ - 2186 Popular Cows(强连通缩点)
题目链接:点击查看
题目大意:给出n只奶牛,以及m组可传递的关系,每组关系给出一个a和一个b,表示为a->b,意思是奶牛a觉得奶牛b很酷,因为关系可传递,所以如果a->b且b->c,能够推出a->c,现在问有多少只奶牛,可以被其他所有的奶牛都认为很酷
题目分析:题目给出的是有向边,且满足条件的奶牛肯定可以被所有的点间接或直接到达,故是一个强联通的题目,我们可以先用tarjan算法将整个有向图缩点,每一个新的点所代表的集合中的点都可以两两互相到达,再根据原图的边建一个新图,找到一个出度为0的点,那么答案就是出度为0的点所代表的集合中点的个数了,注意,若出度为0的点所代表的集合不唯一,那么肯定是无解的,直接输出0就行了,相反,如果出度为0的点不存在,那么说明肯定形成了环,故所有的点都是满足条件的,然后在缩点的时候记录一下每个集合的大小就好了
第二天更新:
第二天学习了有向图的强联通缩点,但实在不明白昨天我是怎么用无向图的点双缩点给乱搞出来的。。特地回去写了一发应该算是正解代码贴上吧,其实也是模板题,直接用tarjan强联通缩点就行了
代码:
无向图点双缩点:
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e4+100;struct Egde
{int to,next;
}edge[N*10];int head[N],low[N],dfn[N],num,tot,c[N],dcc,out[N];bool bridge[N*10];vector<int>ans[N];void addedge(int u,int v)
{edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++;
}void tarjan(int u,int in_edge)
{dfn[u]=low[u]=++num;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;if(!dfn[v]){tarjan(v,i);low[u]=min(low[u],low[v]);if(low[v]>dfn[u])bridge[i]=bridge[i^1]=true;}else if(i!=(in_edge^1))low[u]=min(low[u],dfn[v]);}
}void dfs(int u)
{c[u]=dcc;ans[dcc].push_back(u);for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;if(c[v]||bridge[i])continue;dfs(v);}
}void init()
{for(int i=0;i<N;i++)ans[i].clear();tot=num=dcc=0;memset(head,-1,sizeof(head));memset(low,0,sizeof(low));memset(dfn,0,sizeof(dfn));memset(bridge,false,sizeof(bridge));memset(c,0,sizeof(c));memset(out,0,sizeof(out));
}int main()
{
// freopen("input.txt","r",stdin);
// ios::sync_with_stdio(false);int n,m;while(scanf("%d%d",&n,&m)!=EOF){init();while(m--){int u,v;scanf("%d%d",&u,&v);addedge(u,v);addedge(v,u);}for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i,0);for(int i=1;i<=n;i++)if(!c[i]){dcc++;dfs(i);}for(int i=0;i<tot;i+=2){int u=edge[i^1].to;int v=edge[i].to;if(c[u]!=c[v])out[c[u]]++;}int cnt=0,mark;for(int i=1;i<=dcc;i++)if(out[i]==0){cnt++;mark=ans[i].size();}if(cnt==1)printf("%d\n",mark);else if(cnt==0)printf("%d\n",n);elseputs("0");}return 0;
}
有向图强联通缩点:
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e4+100;const int M=5e4+100;struct Egde
{int to,next;
}edge1[M],edge2[M];int head1[N],head2[N],low[N],dfn[N],c[N],Stack[N],num,cnt,cnt2,cnt1,dcc,n,m,top,out[N];bool ins[N];vector<int>scc[N];void addedge1(int u,int v)
{edge1[cnt1].to=v;edge1[cnt1].next=head1[u];head1[u]=cnt1++;
}void addedge2(int u,int v)
{edge2[cnt2].to=v;edge2[cnt2].next=head2[u];head2[u]=cnt2++;
}void tarjan(int u)
{dfn[u]=low[u]=++num;Stack[++top]=u;ins[u]=true;for(int i=head1[u];i!=-1;i=edge1[i].next){int v=edge1[i].to;if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);}else if(ins[v])low[u]=min(low[u],dfn[v]);}if(dfn[u]==low[u]){cnt++;int v;do{v=Stack[top--];ins[v]=false;c[v]=cnt;scc[cnt].push_back(v);}while(u!=v);}
}void solve()
{for(int i=1;i<=n;i++)//缩点 if(!dfn[i])tarjan(i);
}void build()//缩点+连边
{solve();for(int i=1;i<=n;i++){for(int j=head1[i];j!=-1;j=edge1[j].next){int u=i;int v=edge1[j].to;if(c[u]!=c[v])addedge2(c[u],c[v]);}}
}void init()
{for(int i=0;i<N;i++)scc[i].clear();top=cnt=cnt1=cnt2=num=dcc=0;memset(head2,-1,sizeof(head2));memset(head1,-1,sizeof(head1));memset(low,0,sizeof(low));memset(dfn,0,sizeof(dfn));memset(c,0,sizeof(c));memset(ins,false,sizeof(ins));memset(out,0,sizeof(out));
}int main()
{
// freopen("input.txt","r",stdin);
// ios::sync_with_stdio(false);while(scanf("%d%d",&n,&m)!=EOF){init();while(m--){int u,v;scanf("%d%d",&u,&v);addedge1(u,v);}build();for(int i=1;i<=cnt;i++){for(int j=head2[i];j!=-1;j=edge2[j].next){int u=i;int v=edge2[j].to;if(u!=v)out[u]++;}}int tot=0,mark;for(int i=1;i<=cnt;i++)if(out[i]==0){tot++;mark=scc[i].size();}if(tot==1)printf("%d\n",mark);else if(tot==0)printf("%d\n",n);elseputs("0");}return 0;
}
POJ - 2186 Popular Cows(强连通缩点)相关推荐
- Poj 2186 Popular Cows(Tarjan 强连通缩点)
传送门:Poj 2186 题意:给你n头牛,m种关系,A牛认为B牛是popular的,B牛认为C牛是popular的,则A也认为C是popular的,问最终有几头被所有牛认为是popular的牛 题解 ...
- POJ 2186 Popular Cows(强连通分量缩点,Tarjan算法)
[题目链接] http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=16578 [解题报告] 给你一个有向图,问你有多少个点可以被其它 ...
- pku 2186 Popular Cows (tarjan缩点)
http://poj.org/problem?id=2186 将所有最大连通分量缩点,然后统计缩点后每个点的出度,出度为0的肯定就是了可是这个点可能是缩出来的,所以要记录这个点真正包含的点数.如果出度 ...
- POJ 2186 Popular Cows (强联通分量)
链接 :http://poj.org/problem?id=2186 一个联通分量里的所有的牛满足任何一个被其他牛认为是红人.强联通缩点之后 只需要找到一个且只有一个联通分量且它的出度为0 答案就是这 ...
- POJ 2186 Popular Cows(Tarjan)
http://poj.org/problem?id=2186 题意 :给你n头牛,m对关系,每对关系由两个编号组成,u和v代表着u认为v是受欢迎的,如果1认为2是受欢迎的,2认为3是受欢迎的,那1认为 ...
- POJ 2186 Popular Cows
POJ_2186 这个题目其实就是求完强连通分量之后,判断一下出度为0的强连通分量是否唯一,如果唯一输出该强连通分量的点数,否则输出0. 由于之前求强连通分量的时候是把同一个强连通分量里的数放到一个数 ...
- POJ 2186 popular cow 有向图的强联通问题 Tarjan算法
参考:http://hi.baidu.com/1093782566/blog/item/e5a0e9229913bd048b82a175.html http://www.cppblog.com/Iro ...
- POJ-2186 Popular Cows (Tarjan缩点) 文末有测试数据
题目链接 NNN个牛,MMM个关系 (A,B)A(A,B)A(A,B)A认为BBB是受欢迎的.求受所有牛欢迎的牛的数量. 思路 同一个强联通分量里面的牛是相互受欢迎的,我们将所有的联通分量求出来之后, ...
- POJ 2168 Popular Cows
在zyh的高中,学生会每一年都会评选受欢迎学生,所谓受欢迎的学生,就是被所有学生喜欢的学生. 每个学生都喜欢自己,碰巧的是,如果学生A 喜欢学生B ,学生B喜欢学生C, 那么学生A也喜欢学生C. 但是 ...
最新文章
- 使用Epoll 能监听普通文件吗?
- Android 如何使用GPU硬件加速
- 苍天啊,请你不要再哭泣
- 深入理解三次握手四次挥手以及使用scapy实现ddos雏形
- npm 更改默认全局路径以及国内镜像
- 第一讲 工作区和GOPATH
- saltstack php,Saltstack快速入门简单汇总
- 【clickhouse】clickhouse数据文件目录移动到新目录并建立软连接
- android反编译工具 ApkDec-Release-0.1
- 从入门到入土:nmap出击:使用nmap扫描某台靶机,给出并解读靶机环境的配置情况
- 阶段2 JavaWeb+黑马旅游网_15-Maven基础_第3节 maven标准目录结构和常用命令_07maven常用命令...
- 高中信息技术html语言,高中信息技术Frontpage试题
- My Sixteenth Page - 四数相加 - By Nicolas
- Python快速实现视频播放器
- 1.什么情况下发生GC
- Linux下Chelsio T5调试方法
- 计算机软件侵害,如何认定侵害计算机软件著作权?
- 超级壁纸android,【教程】MIUI最新超级壁纸安卓全机型安装指南
- 基于脑机接口的人脑控制机械手臂
- 利用微软接口制作的文字转语音神器Read Aloud