poj2186 Popular Cows

题目很短,大意是给你牛和牛之间相互仰慕的状况,如果A仰慕B,B仰慕C则A必定仰慕C,要求输出被所有牛仰慕的牛有多少。
首先题目要求的牛要被所有的牛仰慕,那显然必须构成一个联通图
那么每一个点都要有入度或者出度,考虑这种情况:如果某只牛没有出度,那么就意味着他不仰慕别的牛只是被别人仰慕,由于又是 连通图,具题目要求仰慕又有传递性,那么必须这只牛被所有的牛仰慕,
现在假设这只牛变成了一个强连通分量,那么显然意味着这个分量里面的牛都被YM,所以解题的方法就应该是在缩点之后的图G中求出所有出度为零的点的个数,如果个数大于1,说明至少存在两个分量之间的牛不会相互YM,明显和题目要求不符合,输出0,如果等于1则说明只有一个强连通分量里面的牛被其他全部的牛YM,那么答案就是这个分量中点的个数

这题纠结了蛮久,之前对缩点后求度数不是很清楚,然后代码一直WA,在参阅了某MM的博客后做了多组数据,发现了不少bug,修改了好久才AC。。。唉。。。 

#include <iostream>
#include <vector>
#include <map>
using namespace std;
const int size = 11000;
vector <int> mapp[size], remapp[size];
vector <int>comp[size];
vector <int>sccindex[size];
map <int, int> mak;
bool visited[size];
int num[size];
int belg[size];
int counter;
int n ;
int edge[5*size][2]; //0记录出点,1记录入点 
void init()
{
     for (int i = 0; i <= n; i ++){
         mapp[i].clear(), remapp[i].clear(), comp[i].clear(), sccindex[i].clear();    
     }    
     mak.clear(); 
}
void dfs1(int v)
{
     visited[v] = true;
     for (int i = 0; i < mapp[v].size(); i ++){
         int t = mapp[v][i];
         if (!visited[t]){
            dfs1(t);                 
         }    
     }
     num[++counter]= v;
}
int kk;
void dfs2(int v)
{
     visited[v] = true;
     sccindex[kk].push_back(v);//记录第kk个强连通分量中的点 
     mak[v] = kk;//记录第kk个点属于第几个强连通分量 
     for (int i = 0; i < remapp[v].size(); i ++){
         int t = remapp[v][i];
         if (!visited[t]){
            belg[t] = kk;
            dfs2(t);                 
         }    
     } 
     
}


void scc()
{
     counter = 0;
     memset(visited, false, sizeof(visited));
     for (int i = 1; i <= n; i ++){
         if (!visited[i]){
            dfs1(i);
         }
     }     
    // cout<<"counter: "<<counter<<endl;
     memset(visited, false ,sizeof(visited));
     kk = 0;
     for (int i = counter; i >= 1; i --){
         int k = num[i];
         if (!visited[k]){
            visited[k] = true;
            ++ kk;
            dfs2(k); 
            
         }    
     } 
}


void compress()
{
     for (int i = 1; i <= n; i ++){
         for (int j = 0; j < mapp[i].size(); j ++){
             if (belg[mapp[i][j]] != belg[i]){
                comp[belg[i]].push_back(belg[mapp[i][j]]);                        
             }    
         }    
     }     
}
int main()
{
    //freopen("IN.txt", "r", stdin);
    //freopen("OUT.txt", "w", stdout);
    int m;
    while (scanf("%d%d", &n, &m) != EOF){
          init();
          int t;
          int a, b;
          for (int i = 0; i < m; i ++){
              scanf("%d%d", &a, &b);
              edge[i][0] = a;
              edge[i][1] = b; 
              mapp[a].push_back(b);
              remapp[b].push_back(a);
          }
          scc();
          compress();
          int OUT[size] = {0}; 
          int maxx = -1;
          for (int i = 0; i < m; i ++){
              a = mak[edge[i][0]], b = mak[edge[i][1]];//a,b表示每个出点入点所在的强连通分量位置
              if (a != b){
                 OUT[a] ++;    
              } 
          }
          int ans = 0;
          int id;
          for (int i = 1; i <= kk; i ++){
              if (!OUT[i]){ans ++;id = i;}
          }
          if (ans == 1){
             printf("%d\n", sccindex[id].size()) ;          
          }
          else
          printf("0\n");
    }
    return 0;    
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值