Papa的朋友圈(原POJ 2186)Tarjan
Posted qseer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Papa的朋友圈(原POJ 2186)Tarjan相关的知识,希望对你有一定的参考价值。
题目描述
Papa朋友圈里的每一个人都梦想成为朋友圈里的网红。被所有人喜欢的人就是一个网红。Papa所有的朋友都是自恋狂,每个人总是喜欢自己的。人与人之间的“喜欢”是可以传递的——如果A喜
欢B,B喜欢C,那么A也喜欢C。Papa的朋友圈里共有N 个人,给定一些这些人之间的喜欢关系,请你算出有多少个人可以当网红。
输入格式:
第一行:两个用空格分开的整数:N和M
第二行到第M + 1行:每行两个用空格分开的整数:A和B,表示A喜欢B
输出格式:
第一行:单独一个整数,表示朋友圈网红的数量
输入样例:
3 3
1 2
2 1
2 3
输出样例:
1
说明
只有 3 号可以做网红
【数据范围】
10%的数据N<=20, M<=50
30%的数据N<=1000,M<=20000
70%的数据N<=5000,M<=50000
100%的数据N<=10000,M<=50000
虽然是道Tarjan裸题,但没有学长指导确实自己做不出来
解析:
这道题我们用一个双端队列(vctor)来储存A 喜欢 B,相当于建一条 A 指向 B 的单向边
如图
本来的关系应是这样:
Tarjan后:
我们用一个 degree[] 储存出口,在两点不为强联通分量时才存在出口,因此我们把出口的degree保持为 0,其余则改变为true
讲道理出口有且仅有一个
如果存在两个出口,那答案一定为0 —— 一定有两人互不喜欢,就不满足条件啦
MY:
#include<stdio.h> #include<algorithm> #include<stack> #include<vector> using namespace std; const int MX=10001; int n,m,k,cnt,dfn[MX],low[MX],belong[MX],degree[MX]; bool vis[MX]; stack<int> stk; vector<int> mp[MX]; void Tarjan(int x) { dfn[x]=low[x]=++k; vis[x]=1; stk.push(x); for(int j=0;j<mp[x].size();++j) { int next=mp[x][j]; if(!dfn[next]) { Tarjan(next); low[x]=min(low[x],low[next]); } else { low[x]=min(low[x],dfn[next]); } } if(dfn[x] == low[x]) { int top; cnt++; do { top=stk.top(); stk.pop(); belong[top]=cnt; }while(top!=x); } } void sol() { int ans=0,sum=0,index; for(int i=1;i<=n;++i) { for(int j=0;j<mp[i].size();++j) { if(belong[i] != belong[mp[i][j]]) degree[belong[i]]++; } } for(int i=1;i<=cnt;++i) { if(!degree[i]) sum++,index=i; } if(sum>1) { printf("0"); } else { for(int i=1;i<=n;++i) { if(belong[i] == index) { ans++; } } printf("%d",ans); } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;++i) { int a,b; scanf("%d%d",&a,&b); mp[a].push_back(b); } for(int i=1;i<=n;++i) { if(!dfn[i]) Tarjan(i); } sol(); return 0; }
学长滴:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<stdlib.h> #include<vector> #include<stack> using namespace std; #define N 10005 stack<int> sta; vector<int> mp[N]; int dfn[N],low[N],vis[N],num[N],degree[N]; int n,m,cnt,id,ans; void init(){ cnt=0; id=0; ans=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); memset(num,0,sizeof(num)); memset(degree,0,sizeof(degree)); while(!sta.empty()) sta.pop(); for(int i=1;i<=n;i++) mp[i].clear(); } void tarjan(int x){ dfn[x]=low[x]=++id; sta.push(x); vis[x]=1; for(int i=0;i<mp[x].size();i++){ int t=mp[x][i]; if(!dfn[t]) { tarjan(t); low[x]=min(low[x],low[t]); } else if(vis[t]) low[x]=min(low[x],dfn[t]); } if(dfn[x]==low[x]){ int tp; cnt++; do{ tp=sta.top(); vis[tp]=0; num[tp]=cnt; sta.pop(); }while(tp!=x); } } void solve(){ int sum=0,index; for(int i=1;i<=n;i++){ for(int j=0;j<mp[i].size();j++){ if(num[i]!=num[mp[i][j]]) degree[num[i]]++; } } for(int i=1;i<=cnt;i++){ if(!degree[i]) sum++,index=i; } if(sum>1) cout<<"0"<<endl; else { for(int i=1;i<=n;i++) if(num[i]==index) ans++; cout<<ans<<endl; } } int main(){ while(cin>>n>>m){ init(); for(int i=0;i<m;i++){ int a,b; cin>>a>>b; mp[a].push_back(b); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); solve(); } } /* 3 4 1 2 2 1 2 3 3 2 */
以上是关于Papa的朋友圈(原POJ 2186)Tarjan的主要内容,如果未能解决你的问题,请参考以下文章
POJ2186 Popular Cows [tarjan 缩点]
POJ 2186 Popular Cows tarjan缩点算法