zoukankan      html  css  js  c++  java
  • P2341 [HAOI2006]受欢迎的牛

    Description:

    每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶
    牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜
    欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你
    算出有多少头奶牛可以当明星。

    Analysis:

    显然强连通分量里的点都互相喜欢,跑tarjan求强连通分量,统计每个强连通分量的出度,如果有一个强连通分量出度为0,则输出该强连通分量的大小。若同时存在多个强连通分量出度为0,则不满足题意,输出0。

    Code:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<stack>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int maxn = 10001;
    const int maxm = 50005;
    int s[maxn],top;
    //stack<int> s;
    struct edge{
    	int next,to;
    }e[maxm];
    //	dfn[] := dfs序,low[] := 该点及其子树所能追溯的的最小的dfn值
    //	scc[] := 属于哪个强连通分量,Scc[] := 强连通分量的大小
    //	in[] := 强连通分量的入度,out[] := 强连通分量的出度
    int head[maxn],dfn[maxn],low[maxn],scc[maxn],Scc[maxn],in[maxn],out[maxn],num_dfs,num_scc,num_edge,n,m,cnt,ans;
    void tarjan(int u){
    	dfn[u] = low[u] = ++num_dfs;
    	s[++top] = u;
    	//s.push(u);
    	for(int i = head[u];i;i = e[i].next){
    		int v = e[i].to;
    		if(!dfn[v]){
    			//如果v未访问,则继续递归 
    			tarjan(v);
    			low[u] = min(low[u],low[v]);
    		}else{
    			if(!scc[v])
    				low[u] = min(low[u],dfn[v]);
    		}
    	}
    	if(low[u] == dfn[u]){
    		++num_scc;
    		Scc[num_scc]++;
    		scc[u] = num_scc;
    		while(s[top] != u){
    			Scc[num_scc]++;
    			scc[s[top]] = num_scc;//同一个强连通分量的点放在栈中 
    			--top;
    		}
    		--top;
    	}
    }
    void add(int from,int to){
    	e[++num_edge].next = head[from];
    	e[num_edge].to = to;
    	head[from] = num_edge;
    }
    int main(){ 
    	scanf("%d %d",&n,&m); 
    	for(int i = 1;i <= m;i++){
    		int a,b;
    		scanf("%d %d",&a,&b);
    		add(a,b);
    	}
    	//tarjan找强连通分量 
    	for(int i = 1;i <= n;i++){
    		if(!dfn[i]) tarjan(i);
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=head[i];j;j=e[j].next){
    			int t = e[j].to;
    			//枚举原图中的两个相连的点,若不属于同一个强连通分量,则其入度、出度分别+1 
    			if(scc[i] != scc[t])
    				in[scc[t]]++,out[scc[i]]++;
    		}
    	}
    	//if(scc[i]!=scc[t]) outd[belong[i]]++,ind[belong[t]]++;
    	ans = 0;
    	for(int i = 1;i <= num_scc;i++){
    		if(!out[i]){
    			if(ans){
    				//如果存在多个出度为0的强连通分量,则无解 
    				ans = 0;
    				break;
    			}
    			else{
    				ans = Scc[i];
    			}
    		}
    	}
    	printf("%d",ans);
    	return 0;
    }
    
    岂能尽如人意,但求无愧我心
  • 相关阅读:
    图说jdk1.8新特性(3)--- 注解与类型推测优化
    图说jdk1.8新特性(2)--- Lambda
    图说jdk1.8新特性(1)--- 函数式接口
    Linux应用与端口
    Linu如何查看磁盘占用情况及处理办法
    ThreadLocal剧集(一)
    缓存穿透、缓存击穿、缓存雪崩区别和解决方案
    MySQL 新建用户,为用户授权,指定用户访问数据库
    2019面试总结
    Java的设计模式
  • 原文地址:https://www.cnblogs.com/Zforw/p/10611008.html
Copyright © 2011-2022 走看看