BZOJ 1051 受欢迎的牛 强连通块
自力更生,艰苦创业。没错,相信自己,能行的。这道题我的思路大概很明显这是个有向图,先求出各自的强连通块,然后缩点,形成一个DAG,然后在这上面跑 dp。 如果有一个强连通分量的值为所有的点数那么该连通块内点的个数即为答案。其实有向无环图上的dp是很经典的,要多注意。加油,相信自己。对了,这里面据说有很多边是重复的,那么在缩点的时候,因为是DAG,所以用并查集来判断两个强连通分量之间是否已经有连边。
1 #include<cstdio> 2 #include<iostream> 3 #include<stack> 4 #include<vector> 5 #define rep(i,j,k) for(int i = j; i <= k; i++) 6 #define maxn 10005 7 using namespace std; 8 9 vector<int> g1[maxn], b[maxn], g2[maxn]; 10 11 int read() 12 { 13 int s = 0, t = 1; char c = getchar(); 14 while( !isdigit(c) ){ 15 if( c == '-' )t = -1; c = getchar(); 16 } 17 while( isdigit(c) ){ 18 s = s * 10 + c - '0'; c = getchar(); 19 } 20 return s * t; 21 } 22 23 int pre[maxn], low[maxn], cnt = 0, bcnt = 1; 24 int sccno[maxn], num[maxn]; 25 stack<int> s; 26 27 void dfs(int now) 28 { 29 s.push(now); pre[now] = low[now] = ++cnt; 30 int sz = g1[now].size(); 31 rep(i,0,sz-1){ 32 int to = g1[now][i]; 33 if( !pre[to] ){ 34 dfs(to), low[now] = min(low[now],low[to]); 35 } 36 else if( !sccno[to] ) low[now] = min(low[now],pre[to]); 37 38 } 39 if( pre[now] == low[now] ){ 40 for(;;){ 41 int x = s.top(); s.pop(); 42 b[bcnt].push_back(x); 43 num[bcnt]++; 44 sccno[x] = bcnt; 45 if( x == now ) break; 46 } 47 bcnt++; 48 } 49 } 50 51 int fa[maxn], rank[maxn]; 52 int find(int x) 53 { 54 return x == fa[x] ? x : fa[x] = find(fa[x]); 55 } 56 bool bing(int x,int y) 57 { 58 int kx = find(x), ky = find(y); 59 if( kx != ky ){ 60 if( rank[kx] > rank[ky] ){ 61 fa[ky] = kx; rank[kx] += 1; 62 } 63 else { 64 fa[kx] = ky, rank[ky] += 1; 65 } 66 return 1; 67 } 68 else return 0; 69 } 70 71 void suo() 72 { 73 rep(i,1,bcnt-1) fa[i] = i; 74 rep(i,1,bcnt-1){ 75 int s = b[i].size(); 76 rep(j,0,s-1){ 77 int x = b[i][j]; 78 int sz = g1[x].size(); 79 rep(k,0,sz-1){ 80 int to = g1[x][k]; 81 if( sccno[to] != sccno[x] ){ 82 if( bing(sccno[to],sccno[x]) ) 83 { 84 g2[sccno[x]].push_back(sccno[to]); 85 } 86 } 87 } 88 } 89 } 90 } 91 92 int n, m, f[maxn]; 93 94 int road(int now) 95 { 96 if( f[now] ) return f[now]; 97 f[now] = 0; 98 int s = g2[now].size(); 99 rep(i,0,s-1){ 100 int to = g2[now][i]; 101 f[now] += road(to); 102 } 103 return f[now] += num[now]; 104 } 105 106 int solve() 107 { 108 rep(i,1,bcnt-1){ 109 if( !f[i] ) road(i); 110 } 111 int ans = 0; 112 rep(i,1,bcnt-1){ 113 if( f[i] == n ) ans += num[i]; 114 } 115 return ans; 116 } 117 118 int main() 119 { 120 n = read(), m = read(); 121 rep(i,1,m){ 122 int x = read(), y = read(); 123 g1[y].push_back(x); 124 } 125 rep(i,1,n){ 126 if( !pre[i] ) dfs(i); 127 } 128 suo(); 129 cout<<solve()<<endl; 130 return 0; 131 }
————————————————