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

题目直接摆在这里!

1051: [HAOI2006]受欢迎的牛

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 4438  Solved: 2353
[Submit][Status][Discuss]

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 Input

3 3
1 2
2 1
2 3

Sample Output

1

HINT

100%的数据N<=10000,M<=50000

Source

[Submit][Status][Discuss]

这道题和codevs2822爱在心中类似,也是一道tarjan练手题,所以具体的tarjan板子我就不再贴出来了。

这道题的思路也可以和codevs2822一样的,使用tarjan+SPFA,但是由于本人太懒,不想再打140行代码,就换了另一种思路。

正解:tarjan缩点

具体做法:

第一步,先读入数据建边;

第二步,开始跑tarjan,别忘记在tarjan过程中要缩点,接下来的过程要用到。(所谓缩点,就是把每个点都归到一个强联通块里面,对强联通块进行操作)

第三步:根据m个边的关系,统计每个强联通块的出度。

第四步:统计出度为0的强联通块的个数,若为1,则输出次强联通块组成元素个数,否则输出0。(这里才是这道题目核心的思想,想一想为什么,其实很简单)。

先贴上代码(建议大家不要用vector这种东西,数据结构尽量手写)

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cmath>
  4 #include <cstring>
  5 #include <cstdlib>
  6 #include <algorithm>
  7 #include <stack>
  8 using namespace std;
  9 int get_num(){
 10     int num = 0;
 11     char c;
 12     bool flag = false;
 13     while((c = getchar()) == ‘ ‘ || c == ‘\r‘ || c == ‘\n‘);
 14     if(c == ‘-‘)
 15         flag = true;
 16     else num = c - ‘0‘;
 17     while(isdigit(c = getchar()))
 18         num = num * 10 + c - ‘0‘;
 19     return (flag ? -1 : 1) * num;
 20 }
 21 const int maxn = 1e4 + 5;
 22 const int maxm = 5e4 + 5;
 23 int n,m,h[maxn],sccno[maxn],scc_cnt,id[maxn],sum,r[maxn],dfn[maxn],low[maxn],dfs_clock,ans,pos;
 24 stack<int>s;
 25 struct edge{
 26     int fr,to,next;
 27 }edges[maxm << 1];
 28 void addedge(int u,int v){
 29     edges[sum].fr = u;
 30     edges[sum].to = v;
 31     edges[sum].next = h[u];
 32     h[u] = sum++;
 33 }
 34 void init(){
 35     memset(id,0,sizeof(id));
 36     memset(sccno,0,sizeof(sccno));
 37     memset(r,0,sizeof(r));
 38     memset(h,-1,sizeof(h));
 39     memset(edges,0,sizeof(edges));
 40     sum = 0;
 41     dfs_clock = 0;
 42     memset(dfn,0,sizeof(dfn));
 43     memset(low,0,sizeof(low));
 44 }
 45 void tarjan(int u){
 46     dfn[u] = low[u] = ++dfs_clock;
 47     s.push(u);
 48     for(int i = h[u];i != -1;i = edges[i].next){
 49         edge e = edges[i];
 50         if(!dfn[e.to]){
 51             tarjan(e.to);
 52             low[u] = min(low[u],low[e.to]);
 53         }
 54         else if(!id[e.to])
 55             low[u] = min(low[u],dfn[e.to]);
 56     }
 57     if(low[u] == dfn[u]){
 58         scc_cnt++;
 59         while(true){
 60             int x = s.top();
 61             s.pop();
 62             sccno[scc_cnt] += 1;
 63             id[x] = scc_cnt;
 64             if(x == u)break;
 65         }
 66     }
 67     return;
 68 }
 69 void find_tarjan(){
 70     for(int i = 1;i <= n;++i){
 71         if(!dfn[i])
 72             tarjan(i);
 73     }
 74     return;
 75 }
 76 int main(){
 77     int a,b;
 78     init();
 79     n = get_num();
 80     m = get_num();
 81     for(int i = 1;i <= m;++i){
 82         a = get_num();
 83         b = get_num();
 84         addedge(a,b);
 85     }
 86     find_tarjan();
 87     for(int i = 0;i < sum;++i){
 88         int x = edges[i].fr;
 89         int y = edges[i].to;
 90         if(id[x] != id[y])
 91             r[id[x]]++;
 92     }
 93     ans = 0;
 94     for(int i = 1;i <= scc_cnt;++i){
 95         if(r[i] == 0){
 96             if(!ans)
 97                 ans = sccno[i];
 98             else{
 99                 ans = 0;
100                 break;
101             }
102         }
103     }
104     printf("%d\n",ans);
105     return 0;
106 }

这次解题报告就写到这里吧,NOIP倒计时两个月,祝大家能考个好成绩!

时间: 2024-08-03 07:28:57

BZOJ 1051 最受欢迎的牛 解题报告的相关文章

bzoj 1051: [HAOI2006]受欢迎的牛 tarjan缩点

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

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

洛谷 P2341 BZOJ 1051 [HAOI2006]受欢迎的牛

题目描述 每头奶牛都梦想成为牛棚里的明星.被所有奶牛喜欢的奶牛就是一头明星奶牛.所有奶 牛都是自恋狂,每头奶牛总是喜欢自己的.奶牛之间的“喜欢”是可以传递的——如果A喜 欢B,B喜欢C,那么A也喜欢C.牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你 算出有多少头奶牛可以当明星. 输入输出格式 输入格式: ? 第一行:两个用空格分开的整数:N和M ? 第二行到第M + 1行:每行两个用空格分开的整数:A和B,表示A喜欢B 输出格式: ? 第一行:单独一个整数,表示明星奶牛的数量 输入输出样

BZOJ 1051: [HAOI2006]受欢迎的牛

Description 一个有向图,求所以能被别的点到达的点的个数. Sol Tarjan + 强连通分量 + 缩点. 缩点以后找强连通分量,缩点,然后当图有且仅有1个出度为1的点时,有答案. Code /************************************************************** Problem: 1051 User: BeiYu Language: C++ Result: Accepted Time:76 ms Memory:3048 kb *

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

1051: [HAOI2006]受欢迎的牛

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

【BZOJ1051】1051: [HAOI2006]受欢迎的牛 tarjan求强连通分量+缩点

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 Input 3 3

洛谷1051 谁拿了最多奖学金 解题报告

洛谷1051 谁拿了最多奖学金 本题地址:http://www.luogu.org/problem/show?pid=1051 题目描述 某校的惯例是在每学期的期末考试之后发放奖学金.发放的奖学金共有五种,获取的条件各自不同: 1)     院士奖学金,每人8000元,期末平均成绩高于80分(>80),并且在本学期内发表1篇或1篇以上论文的学生均可获得: 2)     五四奖学金,每人4000元,期末平均成绩高于85分(>85),并且班级评议成绩高于80分(>80)的学生均可获得: 3)

openjudge 2971:抓住那头牛 解题报告

总时间限制: 2000ms 内存限制:  65536kB 描述 农夫知道一头牛的位置,想要抓住它.农夫和牛都位于数轴上,农夫起始位于点N(0<=N<=100000),牛位于点K(0<=K<=100000).农夫有两种移动方式: 1.从X移动到X-1或X+1,每次移动花费一分钟. 2.从X移动到2*X,每次移动花费一分钟. 假设牛没有意识到农夫的行动,站在原地不动.农夫最少要花多少时间才能抓住牛? 输入 两个整数,N和K 输出 一个整数,农夫抓到牛所要花费的最小分钟数 样例输入 5