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 }
时间: 2024-10-02 06:54:45

BZOJ 1051 受欢迎的牛 强连通块的相关文章

【强连通分量】bzoj 1051 受欢迎的牛

1051: [HAOI2006]受欢迎的牛 时间限制: 10 Sec  内存限制: 162 MB提交: 2150  解决: 1129[提交][] 题目描述 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎.你的任务是求出有多少头牛被所有的牛认为是受欢迎的. 输入 第一行两个数N,M. 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重

【tarjan】BZOJ 1051:受欢迎的牛

1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3134  Solved: 1642[Submit][Status][Discuss] Description 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎.你的任务是求出有多少头牛被所有的牛认为是受欢迎的. Inp

BZOJ 1051 受欢迎的牛

强连通分量. #include<iostream>#include<cstdio>#include<cstring>#include<stack>#define maxv 10050#define maxe 50050using namespace std;struct edge{ int v,nxt;}e[maxe];stack <int> s;int n,m,a,b,times=0,dfn[maxv],low[maxv],nume=0,g[m

BZOJ1051|HAOI2006受欢迎的牛|强连通分量

Description每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎.你的任务是求出有多少头牛被所有的牛认为是受欢迎的.Input第一行两个数N,M. 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可能出现多个A,B)Output一个数,即有多少头牛被所有的牛认为是受欢迎的.Sample Input3 31 22 12

BZOJ 1051: [HAOI2006]受欢迎的牛 强连通缩点

题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=1051 题解: 强连通缩点得到DAG图,将图转置一下,对入度为零的点跑dfs看看能不能访问到所有的点. 代码: #include<iostream> #include<cstdio> #include<vector> #include<stack> #include<algorithm> #include<cstring> u

[HAOI2006]受欢迎的牛 [强连通分量]

Description 每头奶牛都梦想成为牛棚里的明星.被所有奶牛喜欢的奶牛就是一头明星奶牛.所有奶牛都是自恋狂,每头奶牛总是喜欢自己的.奶牛之间的"喜欢"是可以传递的--如果A喜欢B,B喜欢C,那么A也喜欢C.牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你算出有多少头奶牛可以当明星. Solution 每个奶牛是一个点,将爱慕关系看成边,建图. 考虑如果途中出现环,那么环上的奶牛都可能是大明星,所以可以把一个强连通分量放在一起考虑. 如果只有一个出度为0的强连通分量,那么里面

bzoj 1051 (强连通) 受欢迎的牛

题目:这里 题意: Description 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这 种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎.你的任务是求出有多少头 牛被所有的牛认为是受欢迎的. Input 第一行两个数N,M. 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可 能出现多个A,B) Output 一个数,即有多少头牛被所有的牛认为是受欢迎的. Samp

[BZOJ 1051][HAOI 2006]受欢迎的牛(tarjan缩点)

http://www.lydsy.com:808/JudgeOnline/problem.php?id=1051 唔...这题好像在POJ上见过? 比较水的题,很好想出思路.牛和牛之间的关系就像有向图,牛a喜欢牛b相当于建立有向边a->b,然后在这个有向图中,每个强连通分量里的牛们相当于是相互喜欢的,把这个图缩点成DAG,DAG里如果有且仅有一个出度为0的点,则这个点对应强连通分量里的所有牛都是受欢迎的牛,如果没有出度为0的点,当然就没受欢迎的牛了,如果出度为0的点的个数大于1,则每个出度为0的

BZOJ 1051 最受欢迎的牛 解题报告

题目直接摆在这里! 1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4438  Solved: 2353[Submit][Status][Discuss] Description 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这 种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎.你的任务是求出有多少头 牛被所有的牛