zoukankan      html  css  js  c++  java
  • 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 == '
    ' || c == '
    ');
     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
    ",ans);
    105     return 0;
    106 }

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

  • 相关阅读:
    Java实现 LeetCode 30 串联所有单词的子串
    Java实现 LeetCode 29 两数相除
    Java实现 LeetCode 29 两数相除
    Java实现 LeetCode 29 两数相除
    Java实现 LeetCode 28 实现strStr()
    Java实现 LeetCode 28 实现strStr()
    Java实现 LeetCode 28 实现strStr()
    Java实现 LeetCode 27 移除元素
    Java实现 LeetCode 27 移除元素
    字符编码终极笔记:ASCII、Unicode、UTF-8、UTF-16、UCS、BOM、Endian
  • 原文地址:https://www.cnblogs.com/gangding/p/5886762.html
Copyright © 2011-2022 走看看