zoukankan      html  css  js  c++  java
  • 题解 P2341 【[USACO03FALL][HAOI2006]受欢迎的牛 G】

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

    终于AC了!

    在这里插入图片描述

    前置知识

    做这道题需要知道 强联通分量 不会的可以学一下。

    分析

    我们发现所以受欢迎的牛一定是一个强联通分量(假设受欢迎的牛是存在的)

    两个强联通分量可以会有横叉边使一个强联通分量可以到达另一个强联通分量。

    这是我们可以把每个强联通分量看成点(这个就是所谓的缩点),就变成了一个普通的有向图。

    我们发现当只有一个点的出度都 (=0) 的话,答案就是那个点了

    否则答案就是 (0)

    为什么?

    首先这个图不会出现环,不然就不满足了强联通分量的性质,强联通分量是有向图的极大强连通子图(极大的意思是不能再加点),那这显然说明了这个图无环。

    这个图无环有说明什么?

    无环就说明这张图不连通,不连通又说明什么?

    说明出度为 (0) 的点至少有 (1) 个。

    为什么出度为 (0) 的点 (> 1) 答案就是 (0) 了呢?

    很显然:

    • 如果出度为 (0) 的点 (> 1) ,肯定没有点能成为明星。

    • 如果出度为 (0) 的点 (= 1) ,那个出度为 (0) 的点肯定就是明星。

    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<stack>
    using namespace std;
    typedef long long ll;
    template<typename T>inline void read(T &FF){
    	T RR=1;FF=0;char CH=getchar();
    	for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
    	for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
    	FF*=RR;
    }
    template<typename T>inline void write(T x){
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar('0'+x%10);
    }
    const int MAXN=1e6+10,MAXM=1e6+10;
    int s[MAXN], stop,dfn[MAXN],low[MAXN],scccnt, sccnum[MAXN],dfscnt,tot,he[MAXN],ne[MAXM<<1],ed[MAXM<<1],n,x,y,sz[MAXN],de[MAXN],ans,m;
    void add(int x,int y){
    	ed[++tot]=y;
    	ne[tot]=he[x];
    	he[x]=tot;
    }
    inline void tarjan(int now){
    	dfn[now] = low[now] = ++dfscnt;
    	s[stop++] = now;
    	for (int i = he[now]; i; i = ne[i]){
    		if(!dfn[ed[i]]){
    			tarjan(ed[i]);
    			low[now] = min(low[now], low[ed[i]]);
    		}else if(!sccnum[ed[i]]) {
    			low[now] = min(low[now], dfn[ed[i]]);
    		}
    	}
    
    	if (dfn[now]==low[now]){
    		scccnt++;
    		do {
    			sccnum[s[--stop]]=scccnt;
    			sz[scccnt]++;
    		}while(s[stop]!=now);
    	}
    }
    int main(){
    	read(n);read(m);
    	for(int i=1;i<=m;i++){
    		read(x);read(y);
    		add(x,y);
    	}
    	for(int i=1;i<=n;i++)
    		if(!dfn[i])tarjan(i);
    	for(int i=1;i<=n;i++)
    		for(int j=he[i];j;j=ne[j])
    			if(sccnum[i]!=sccnum[ed[j]])de[sccnum[i]]++;//记录出度
    	for(int i=1;i<=scccnt;i++)
    		if(!de[i]){//出度为0
    			if(ans){
    				cout<<0;//出度为0的点>1,答案为0
    				return 0;
    			}
    			ans=i;
    		}
    	cout<<sz[ans];//否则就是这个点
    	return 0;
    }
    
  • 相关阅读:
    POJ 1161 Walls ( Floyd && 建图 )
    POJ 1252 Euro Efficiency ( 完全背包变形 && 物品重量为负 )
    POJ 3111 K Best ( 二分 )
    2017乌鲁木齐网络赛 J题 Our Journey of Dalian Ends ( 最小费用最大流 )
    POJ 2112 Optimal Milking ( 经典最大流 && Floyd && 二分 )
    POJ 3281 Dining ( 最大流 && 建图 )
    POJ 2391 Ombrophobic Bovines ( 经典最大流 && Floyd && 二分 && 拆点建图)
    冲刺第一周第一天
    学习进度条12/3到12/9
    四则运算2
  • 原文地址:https://www.cnblogs.com/zhaohaikun/p/13830010.html
Copyright © 2011-2022 走看看