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 }

 

你可能感兴趣的:(BZOJ 1051 受欢迎的牛 强连通块)