poj2553 The Bottom of a Graph

 

题意一开始理解有点小问题,题目大意是说如果一个点v能够到达w并且w也能到v则w和v都称为一个sink,题目要求从大到小输出图中所有的sink点,可能有人会对第二组数据不太理解,看一下这个图

 

显然1有一条边连接到2,如果1是sink点则2也要能够走到1,显然2是sink点因为它没有指向任何点,由此可以看出,只要一个强连通分量没有指向任何点,那么这个分量中的全部点就都是sink点,那么也就是说,只需要输出全部强连通分量出度为0的情况就可以了,记得要排序

 

#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
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", &n) != EOF && n){
          scanf("%d", &m);
          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};
          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[size];
          int id= 0;
          for (int i = 1; i <= kk; i ++){
              if (!OUT[i]){
                 for (int j = 0; j < sccindex[i].size(); j ++){
                     ans[id ++] = sccindex[i][j];   
                 }         
              }
          }
          sort(ans, ans+id);
          for (int i = 0; i < id; i ++){
              if (i)printf(" ");
              printf("%d", ans[i]);   
          }
          printf("\n");
    }
    return 0;   
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值