题面:[USACO03FALL] 受欢迎的牛 G
大秦为你打开题目传送门
题目背景
本题测试数据已修复。
题目描述
每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果 $A$ 喜欢 $B$,$B$ 喜欢 $C$,那么 $A$ 也喜欢 $C$。牛栏里共有 $N$ 头奶牛,给定一些奶牛之间的爱慕关系,请你算出有多少头奶牛可以当明星。
输入格式
第一行:两个用空格分开的整数:$N$ 和 $M$。
接下来 $M$ 行:每行两个用空格分开的整数:$A$ 和 $B$,表示 $A$ 喜欢 $B$。
输出格式
一行单独一个整数,表示明星奶牛的数量。
样例 #1
样例输入 #1
样例输出 #1
提示
只有 $3$ 号奶牛可以做明星。
【数据范围】
对于 $10\%$ 的数据,$N\le20$,$M\le50$。
对于 $30\%$ 的数据,$N\le10^3$,$M\le2\times 10^4$。
对于 $70\%$ 的数据,$N\le5\times 10^3$,$M\le5\times 10^4$。
对于 $100\%$ 的数据,$1\le N\le10^4$,$1\le M\le5\times 10^4$。
思路
首先,显而易见的,这个奶牛的爱慕关系是一个有向图,并且显而易见会出现环,而环就代表了强连通,也就是说可以缩点,所点之后的 DAG 如果有一个点出度为 0 ,就说明他没有爱慕的奶牛了,那么他就是满足条件的。但是说这个点只能有一个,你想想,如果有多个点出度为 0 那么那些出度为 0 的一定得不到所有奶牛的爱慕。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
| #include<bits/stdc++.h> using namespace std;
typedef long long ll;
typedef pair<int , int > pii; typedef unsigned long long ull;
namespace FastIO { template<typename T> inline T read(T& x) { x = 0; int f = 1; char ch; while (!isdigit(ch = getchar())) if (ch == '-') f = -1; while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar(); x *= f; return x; } template<typename T, typename... Args> inline void read(T& x, Args &...x_) { read(x); read(x_...); return; } inline ll read() { ll x; read(x); return x; } }; using namespace FastIO;
const int MaxV = 1e4 + 10; const int MaxE = 5e4 + 10;
template<int N, int M> class Graph { private : struct Edge { int to, nt, wt; Edge() {} Edge(int to, int nt, int wt) : to(to), nt(nt), wt(wt) {} }e[M]; int hd[N], cnte; public : inline void clear() { memset(hd, 0, sizeof(hd)), cnte = 0; } inline void AddEdge(int u, int v, int w = 0) { e[++cnte] = Edge(v, hd[u], w); hd[u] = cnte; } inline int head(int u) { return hd[u]; } inline int nt(int u) { return e[u].nt; } inline int to(int u) { return e[u].to; } inline int wt(int u) { return e[u].wt; } };
int n, m; int uid[MaxE], vid[MaxE]; Graph< MaxV, MaxE >G;
inline void Input() { read(n, m); for(int i = 1; i <= m; i++) { read(uid[i], vid[i]); G.AddEdge(uid[i], vid[i]); } }
int dfn[MaxV], low[MaxV], cntd; stack<int >stk; int instk[MaxV]; int cntc, col[MaxV]; vector<int >clb[MaxV];
void Tarjan(int u) { dfn[u] = low[u] = ++cntd; stk.push(u), instk[u] = 1; for(int i = G.head(u); i; i = G.nt(i)) { int v = G.to(i); if(!dfn[v]) { Tarjan(v); low[u] = min(low[u], low[v]); } else if(instk[v]) { low[u] = min(low[u], dfn[v]); } } if(low[u] == dfn[u]) { ++cntc; int v = stk.top(); stk.pop(); while(v != u) { col[v] = cntc; instk[v] = 0; clb[cntc].push_back(v); v = stk.top(); stk.pop(); } col[v] = cntc; instk[v] = 0; clb[cntc].push_back(v); } }
int otD[MaxV];
inline void Init() { for(int i = 1; i <= m; i++) { if(col[uid[i]] == col[vid[i]]) continue; otD[col[uid[i]]]++; } }
inline void Work() { for(int i = 1; i <= n; i++) { if(dfn[i] == 0) { Tarjan(i); } } Init(); int ans = 0; for(int i = 1; i <= cntc; i++) { if(otD[i] == 0) { if(ans != 0) { printf("0\n"); return ; } ans = clb[i].size(); } } printf("%d\n", ans); }
int main() { int T = 1; while(T--) { Input(); Work(); } return 0; }
|