BZOJ1051: [HAOI2006]受欢迎的牛
来源:互联网 发布:无人机人工智能 编辑:程序博客网 时间:2024/05/18 10:38
Description
每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。
这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。
Input
第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可能出现多个A,B)
Output
一个数,即有多少头牛被所有的牛认为是受欢迎的。
Sample Input
3 3
1 2
2 1
2 3
Sample Output
1
HINT
100%的数据N<=10000,M<=50000
Source
首先建图,根据关系来连边(A认为B受欢迎=A→B)。“必须被所有的牛欢迎”这个条件相当苛刻,那么什么情况下最终的答案会>1?这种情况只会出现在一个强连通分量中(互相觉得对方受欢迎)(当然一个单独结点也可视为一个强连通分量),这个强连通分量中每个节点都是答案,仔细想一想就会发现最终构成答案的强连通分量只会有一个,而且强连通分量中如果有一头牛认为某一头牛受欢迎,那么就可以得到这个强连通分量中所有牛就都认为这头牛受欢迎。利用这个性质,我们就可以依靠强连通分量的算法。
注意:next在某些版本编译器中为关键字,可能导致CE,使用next数组务必小心
方法一:Tarjan后进行DFS并统计次数,若某个强连通分量能被其它所有强连通分量访问到,那它就是答案。
#include<cstdio>#include<algorithm>#include<cstring>#include<iostream>using namespace std;const int N=10010;const int M=50010;int n,m,co,index1,num,next1[M],point[N],to[M];int dfn[N],low[N],t[N],stack[N],top,ans[N],ans1;//i结点所在的强连通分量为t[i],ans[i]统计第i个强连通分量的结点数bool vis[N],vis1[N],vis2[N],instack[N];int ans2[N];void in(int &x){ char t=getchar();int f=1;x=0; while((t<48)or(t>57)){if(t=='-')f=-1;t=getchar();} while((t>=48)and(t<=57)){x=x*10+t-48;t=getchar();} x*=f;}void add(int from,int to1){ ++co; next1[co]=point[from]; point[from]=co; to[co]=to1;}void tarjan(int u){ vis[u]=instack[u]=1; stack[++top]=u; low[u]=dfn[u]=++index1; for (int now=point[u];now;now=next1[now]) { int v=to[now]; if (!vis[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if (instack[v]) low[u]=min(low[u],dfn[v]); } if (dfn[u]==low[u]) { ++num;int v=0; while(v!=u) { v=stack[top--]; t[v]=num;++ans[num]; instack[v]=0; } }}void dfs(int now,int now1){ vis[now]=1; if ((t[now]!=now1)and(!vis1[t[now]])) {++ans2[t[now]];vis1[t[now]]=1;} for (int i=point[now];i;i=next1[i]) { int v=to[i]; if (!vis[v]) dfs(v,now1); }}int main(){ in(n),in(m); for (int i=1;i<=m;++i) { int x,y; in(x),in(y); add(x,y); } for (int i=1;i<=n;++i) if (!vis[i]) tarjan(i); for (int i=1;i<=n;++i) if (!vis2[t[i]]) { memset(vis,0,sizeof(vis)); memset(vis1,0,sizeof(vis1)); dfs(i,t[i]);vis2[t[i]]=1; } for (int i=1;i<=n;++i) if (ans2[t[i]]==(num-1)) {ans1=ans[t[i]];break;} printf("%d",ans1); return 0;}
方法二:利用强连通分量来缩点,把整个强连通分量视为一个结点并重新建图连边,出度为0者即为答案。
注意:可能出现某一个强连通分量被孤立的情况(入度出度都为0),解决方法是把所有强连通分量都扫一遍,如果出现多个出度为0的强连通分量则输出0。
#include<cstdio>#include<algorithm>#include<cstring>#include<iostream>using namespace std;const int N=10010;const int M=50010;int n,m,co,co1,index1,num,next1[M],point[N],to[M];int dfn[N],low[N],t[N],stack[N],top,ans[N],ans1;bool vis[N],instack[N];int point2[N],next2[M],to2[M];void in(int &x){ char t=getchar();int f=1;x=0; while((t<48)or(t>57)){if(t=='-')f=-1;t=getchar();} while((t>=48)and(t<=57)){x=x*10+t-48;t=getchar();} x*=f;}void add(int from,int to1){ ++co; next1[co]=point[from]; point[from]=co; to[co]=to1;}void add1(int from,int to1){ ++co1; next2[co1]=point2[from]; point2[from]=co1; to2[co1]=to1;}void tarjan(int u){ vis[u]=instack[u]=1; stack[++top]=u; low[u]=dfn[u]=++index1; for (int now=point[u];now;now=next1[now]) { int v=to[now]; if (!vis[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if (instack[v]) low[u]=min(low[u],dfn[v]); } if (dfn[u]==low[u]) { ++num;int v=0; while(v!=u) { v=stack[top--]; t[v]=num;++ans[num]; instack[v]=0; } }}void work(int u){ for (int i=point[u];i;i=next1[i]) { int v=to[i]; if (t[v]!=t[u]) add1(t[u],t[v]); }}int main(){ in(n),in(m); for (int i=1;i<=m;++i) { int x,y; in(x),in(y); add(x,y); } for (int i=1;i<=n;++i) if (!vis[i]) tarjan(i); for (int i=1;i<=n;++i) work(i); for (int i=1;i<=num;++i) if (!point2[i]) if (ans1) {ans1=0;break;} else ans1=ans[i]; printf("%d",ans1); return 0;}
- Bzoj1051 haoi2006 受欢迎的牛
- bzoj1051 [HAOI2006]受欢迎的牛
- bzoj1051: [HAOI2006]受欢迎的牛
- [BZOJ1051][HAOI2006]受欢迎的牛
- BZOJ1051[HAOI2006]受欢迎的牛
- BZOJ1051: [HAOI2006]受欢迎的牛
- BZOJ1051 HAOI2006受欢迎的牛
- bzoj1051【HAOI2006】受欢迎的牛
- bzoj1051: [HAOI2006]受欢迎的牛
- bzoj1051 [HAOI2006]受欢迎的牛
- bzoj1051: [HAOI2006]受欢迎的牛
- bzoj1051: [HAOI2006]受欢迎的牛
- BZOJ1051: [HAOI2006]受欢迎的牛
- bzoj1051【HAOI2006】受欢迎的牛
- bzoj1051 [HAOI2006]受欢迎的牛
- bzoj1051 [HAOI2006]受欢迎的牛
- BZOJ1051 [HAOI2006]受欢迎的牛
- 【Bzoj1051】 [HAOI2006]受欢迎的牛
- clip标签的使用
- 解决bootstrap中轮播插件支持手机上的手势滑动的问题
- java中的懒汉单例模式和饿汉单例模式
- 学习一门编程技术需要注意的几个点
- 数据结构——八种排序算法
- BZOJ1051: [HAOI2006]受欢迎的牛
- __pthread_once 源码解析
- UIWebView中 H5双击输入框网页会放缩
- AdapterView学习
- Sublime Text2/3 CTags自动补全
- 欢迎使用CSDN-markdown编辑器
- 将OWL本体文件存储到MySQL数据库
- ios自动布局
- 崩溃信息收集(附代码)