POJ 1236

   

题意:

网络中有一些学校,每个学校可以分发软件给其他学校。可以向哪个分发取决于他们各自维护的一个清单。

有两个问题,1:至少要copy多少份新软件给那些学校, 才能使得每个学校都能得到。

2:要在所有的学校的清单里面至少一共增加几项才能 使得 把软件给任意一个学校,所有的学校都能收得到。

思路:

此题是一个有向图,求有向图的强连同分量+缩点。

先跑一边tarjan算法,缩点。

第一问:入度为0的点的个数即为答案。

第二问:入度或出度为0的个数的较大值为答案,因为缩点之后构成一棵树,树的叶子和根结点都必须和其他的点相连才能构成一个连通图。

 

#include <iostream>
using namespace std; 
  
const int M = 105; 
  
struct Node 
 { 
    int to; 
     Node *next;
 };
 Node *g[M];
 int low[M], stack[M], ord[M], id[M];
 int cnt, scnt;
 bool instack[M], map[M], in[M], out[M];
 void init(int n)
 {
     for(int i=1; i<=n; i++)
     {
         in[i] = true;
         out[i] = true;
        low[i] = 0;
         ord[i] = 0;
         id[i] = 0;
         instack[i] = false;
         map[i] = true;
     }
 }
 
 void insert(int u, int v)
 {
    Node *tmp = new Node;
     tmp -> to = v;
     tmp -> next = g[u];
     g[u] = tmp;
 }
 
 void Tarjan(int n, int e)
 {
     cnt++;
     low[e] = ord[e] = cnt;
     instack[e] = true;
     stack[++stack[0]] = e;
     Node *tmp = g[e];
     
     while (tmp != NULL)
     {
         int t = tmp -> to;

         if(!ord[t])
         {
             Tarjan(n, t);
             if(low[e] > low[t])
                 low[e] = low[t];
         }
         else if(instack[t] && ord[t]<low[e])
             low[e] = ord[t];
         
         tmp = tmp -> next;
     }
     
     if(low[e] == ord[e])
     {
         int t;
         scnt++;
         do
         {
             t = stack[stack[0]--];
             id[t] = scnt;
             instack[t] = false;
             
         }while (t != e);
     }
     
     return ;
 }
 
 void find_compentents(int n)
 {
     cnt = scnt = 0;
     stack[0] = 0;
     for(int i=1; i<=n; i++)
     {
         if(!ord[i])
             Tarjan(n, i);
     }
     return ;
 }
 
 int main()
 {
     int n,i;
    while (scanf("%d",&n)!=EOF)
     {
         init(n);
         for( i=1; i<=n; i++)
         {
             while (1)
            {
                 int a;
                 scanf("%d",&a);
                 if(a == 0)
                     break;

                 insert(i, a);
            }
         }
        
         find_compentents(n);
       
         int ansin = 0, ansout = 0;
         for( i=1; i<=n; i++)
         {
             Node *tmp;
             tmp = g[i];
             while (tmp != NULL)
            {
                 int e = tmp -> to;
                 if(id[i]!=id[e] && out[id[i]])
                     out[id[i]] = false;
                 if(id[i]!=id[e] && in[id[e]])
                     in[id[e]] = false;
                 tmp = tmp -> next;
             }
         }
        
        for( i=1; i<=scnt; i++)
         {
             if(in[i])
                 ansin ++;
             if(out[i])
                 ansout ++;
        }
      
         if(scnt == 1)
             ansout = 0;
        else
             ansout = ansout>ansin ? ansout:ansin;
         printf("%d\n%d\n",ansin,ansout);
        

     }
     return 0;
 }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值