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

    [BZOJ1051][HAOI2006]受欢迎的牛

    试题描述

    每一头牛的愿望就是变成一头最受欢迎的牛。现在有 (N) 头牛,给你 (M) 对整数 ((A,B)),表示牛 (A) 认为牛 (B) 受欢迎。 这种关系是具有传递性的,如果 (A) 认为 (B) 受欢迎,(B) 认为 (C) 受欢迎,那么牛 (A) 也认为牛 (C) 受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。

    输入

    第一行两个数 (N,M)。 接下来 (M) 行,每行两个数 (A,B),意思是 (A) 认为 (B) 是受欢迎的(给出的信息有可能重复,即有可能出现多个 (A,B)

    输出

    一个数,即有多少头牛被所有的牛认为是受欢迎的。

    输入示例

    3 3
    1 2
    2 1
    2 3
    

    输出示例

    1
    

    数据规模及约定

    (100 exttt{%}) 的数据 (N le 10000,M le 50000)

    题解

    强连通分量 tarjan 模板。

    强连通分量缩点后在反图上从入度为 (0) 的点开始 BFS,如果能搜到所有点,就证明那个点中所有牛是“被所有牛受欢迎的”,否则就输出 (0),除此之外没有其他牛了。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    #define rep(i, s, t) for(int i = (s); i <= (t); i++)
    #define dwn(i, s, t) for(int i = (s); i >= (t); i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 10010
    #define maxm 50010
    
    int n;
    
    struct Graph {
    	int m, head[maxn], nxt[maxm], to[maxm];
    	Graph(): m(0) { memset(head, 0, sizeof(head)); }
    	void AddEdge(int a, int b) {
    		to[++m] = b; nxt[m] = head[a]; head[a] = m;
    		return ;
    	}
    } G, D;
    
    int clo, dfn[maxn], low[maxn], cnts, scno[maxn], siz[maxn], S[maxn], top;
    void dfs(int u, int fa) {
    	dfn[u] = low[u] = ++clo;
    	S[++top] = u;
    	for(int e = G.head[u]; e; e = G.nxt[e]) if(G.to[e] != fa) {
    		if(scno[G.to[e]]) continue;
    		if(dfn[G.to[e]]) low[u] = min(low[u], dfn[G.to[e]]);
    		else dfs(G.to[e], u), low[u] = min(low[u], low[G.to[e]]);
    	}
    	if(low[u] == dfn[u]) {
    		cnts++;
    		while(S[top] != u) scno[S[top--]] = cnts, siz[cnts]++;
    		scno[S[top--]] = cnts; siz[cnts]++;
    	}
    	return ;
    }
    
    int ideg[maxn], Q[maxn], hd, tl;
    bool can[maxn];
    void BFS(int s) {
    	can[s] = 1;
    	hd = tl = 0; Q[++tl] = s;
    	while(hd < tl) {
    		int u = Q[++hd];
    		for(int e = D.head[u]; e; e = D.nxt[e])
    			if(!can[D.to[e]]) can[D.to[e]] = 1, Q[++tl] = D.to[e];
    	}
    	return ;
    }
    
    int main() {
    	n = read(); int M = read();
    	rep(i, 1, M) {
    		int a = read(), b = read();
    		G.AddEdge(a, b);
    	}
    	
    	rep(i, 1, n) if(!scno[i]) dfs(i, 0);
    	rep(u, 1, n)
    		for(int e = G.head[u]; e; e = G.nxt[e]) if(scno[G.to[e]] != scno[u]) {
    			D.AddEdge(scno[G.to[e]], scno[u]);
    			ideg[scno[u]]++;
    		}
    	rep(i, 1, cnts) if(!ideg[i]) {
    		BFS(i);
    		bool ok = 1;
    		rep(j, 1, cnts) if(!can[j]){ ok = 0; break; }
    		return printf("%d
    ", ok ? siz[i] : 0), 0;
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    学习windows的半天+学习Git分布式系统的半天
    输出从1加到100的结果、打印100以内的质数、计算一个文件中的每个英文单词出现的次数
    Linux操作系统--初级--进程管理的命令
    Linux操作系统--初级--防火墙
    Linux操作系统--初级--dns服务
    Linux操作系统--初级--网络安全基础
    Linux操作系统--初级--进程管理
    Linux操作系统--初级--Linux网络
    Linux操作系统--初级--Linux磁盘管理
    Linux操作系统--初级--Linux的用户与用户组(权限管理)
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/7808389.html
Copyright © 2011-2022 走看看