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倒计时两个月,祝大家能考个好成绩!

  • 相关阅读:
    windows 乱码之 gbk 与 cp936
    jdcli 在命令行反编译jar包
    建议博客园向独立博客提供发布到首页的服务
    IsByRef在什么情况下为true?
    Hibernate里自定义UserType时取不到值的问题
    解决安装Visual Studio 2010 SP1时被NDP40KB2468871.exe补丁卡死以及mscorsvw.exe进程CPU占用率高的问题
    FROM WAS7/JDK5 TO WAS6/JDK4
    C++山寨C#中的DataTable
    程序员的自我修养读书笔记
    Web开发之路
  • 原文地址:https://www.cnblogs.com/gangding/p/5886762.html
Copyright © 2011-2022 走看看