POJ1236 强连通 (缩点后度数的应用)

题意:
      一些学校有一个发送消息的体系,现在给你一些可以直接发送消息的一些关系(单向)然后有两个问题
(1) 问你至少向多少个学校发送消息可以让所有的学校都得到消息
(2) 问至少加多少条边可以让所有学校达到消息互通(变成强连通图)


思路:
      比较简单了,我们先强连通所点,然后对于第一个问题,我们只要输出入度为0的个数,这个很好理解,对于第二个问题,我们可以输出max(入度为0的个数,出度为0的个数),这样做是因为我们可以吧度数大的先用小的补充上,剩下的就随意补充就行了,还有就是记得只有一个联通分量的时候特判一下,

PS :假如这个题目要是让输出解决方案的话也比较好弄,对于第一个,每个入度为0的点给一个,每个强连通分量《元素个数大于1的》给一个就行了。对于第二个,就是先用小的填充大的,剩下的零头随意安排。


#include<stdio.h>
#include<string.h>
#include<stack>

#define N_node 100 + 10
#define N_edge 10000 + 100

using namespace std;

typedef struct
{
   int to ,next;
}STAR;

typedef struct
{
   int a ,b;
}EDGE;

EDGE edge[N_edge];
STAR E1[N_edge] ,E2[N_edge];
int list1[N_node] ,list2[N_node] ,tot;
int Belong[N_node] ,Cnt;
int mark[N_node];
stack<int>sk;

void add(int a ,int b)
{
   E1[++tot].to = b;
   E1[tot].next = list1[a];
   list1[a] = tot;
   
   E2[tot].to = a;
   E2[tot].next = list2[b];
   list2[b] = tot;
}

void DFS1(int s)
{
   mark[s] = 1;
   for(int k = list1[s] ;k ;k = E1[k].next)
   {
      int to = E1[k].to;
      if(mark[to]) continue;
      mark[to] = 1;
      DFS1(to);
   }
   sk.push(s);
}

void DFS2(int s)
{
   mark[s] = 1;
   Belong[s] = Cnt;
   for(int k = list2[s] ;k ;k = E2[k].next)
   {
      int to = E2[k].to;
      if(mark[to]) continue;
      mark[to]  =1;
      DFS2(to);
   }
}

int main ()
{
   int n ,i ,j ,a;
   while(~scanf("%d" ,&n))
   {
      memset(list1 ,0 ,sizeof(list1));
      memset(list2 ,0 ,sizeof(list2));
      tot = 1;
      int nowid = 0;
      for(i = 1 ;i <= n ;i ++)
      {
         while(scanf("%d" ,&a) && a)
         {
            add(i ,a);
            edge[++nowid].a = i;
            edge[nowid].b = a;
         }
      }
      memset(mark ,0 ,sizeof(mark));
      while(!sk.empty()) sk.pop();
      for(i = 1 ;i <= n ;i ++)
      {
         if(!mark[i]) DFS1(i);
      }
      Cnt = 0;
      memset(mark ,0 ,sizeof(mark));
      while(!sk.empty())
      {
         int xin = sk.top();
         sk.pop();
         if(mark[xin]) continue;
         Cnt ++;
         DFS2(xin);
      }
      int d1[N_node] = {0};
      int d2[N_node] = {0};
      for(i = 1 ;i <= nowid ;i ++)
      {
         int a = Belong[edge[i].a];
         int b = Belong[edge[i].b];
         if(a == b) continue;
         d1[a] ++ ,d2[b] ++;
      }
      int sum1 = 0 ,sum2 = 0;
      for(i = 1 ;i <= Cnt ;i ++)
      {
         if(!d1[i]) sum1 ++;
         if(!d2[i]) sum2 ++;
      }
      if(Cnt == 1)
      {
         printf("1\n0\n");
         continue;
      }
      printf("%d\n" ,sum2);
      sum1 > sum2 ? printf("%d\n" ,sum1) : printf("%d\n" ,sum2);
   }
   return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值