poj 1236

这个题目有点难懂 , (Subtask A)和(Subtask B)是表示两个任务 , 就是两个问题 。
A:求出最少给几个点发送软件 , 才能让所有点都能得到这个软件。
B:在建成的图中 , 最少要增加几条边 ,才能让其变成一个强连通图 。

解法:
A:先求出所有强连通分量 , 然后再用这些分量去建一个图 , 图中入度为0的点 , 就是要发送软件的点 。

代码:
#include
#include
#include
#include
#include
#include
using namespace std;

const int MAXN = 200 ;
vectorgrap[MAXN] , scc[MAXN];
int pre[MAXN] , lowlink[MAXN] , sccno[MAXN];
int n , dfs_clock , scc_cnt;
stacks;

void init()
{
      for(int i = 1 ; i <= n; i++)
      {
            grap[i].clear();
            scc[i].clear();
      }
}

void dfs(int u)  // 寻找强连通分量
{
      lowlink[u] = pre[u] = ++dfs_clock;
      s.push(u);
      for(int i = 0 ; i < grap[u].size() ; i++)
      {
            int v = grap[u][i];
            if(!pre[v])
            {
                  dfs(v);
                  if(lowlink[u] > lowlink[v])  lowlink[u] = lowlink[v];
            }
            else if(!sccno[v] && lowlink[u] > pre[v])
                  lowlink[u] = pre[v];
      }
      if(lowlink[u] == pre[u])
      {
            scc_cnt++;
            for(; ;)
            {
                  int x = s.top() ; s.pop();
                  sccno[x] = scc_cnt;
                  if(x == u)  break;
            }
      }
}

void find_scc()
{
      memset(pre, 0 , sizeof(pre));
      memset(sccno , 0 , sizeof(sccno));
      dfs_clock = scc_cnt = 0;
      for(int i = 1; i <= n; i++)
            if(!pre[i])  dfs(i);
}



int main()
{
      while(scanf("%d" , &n ) != EOF)
      {
            init();
            int i , x , y , j;
            for(i = 1 ; i <= n; i++)
            {
                  for(; ; )
                  {
                        scanf("%d" , &x);
                        if(x == 0)  break;
                        grap[i].push_back(x);
                  }
            }
            find_scc();
            int chu_du[MAXN] , ru_du[MAXN];   
            memset(chu_du , 0 , sizeof(chu_du) );
            memset(ru_du , 0 , sizeof(ru_du));
            for(i = 1; i <= n; i++)
                  for(j = 0 ; j < grap[i].size();  j++)
                  {
                        int v = grap[i][j];
                        x = sccno[i] ; 
                        y = sccno[v];
                        if(x != y) 
                        {
                              scc[x].push_back(y);
                              ru_du[y]++;
                              chu_du[x]++;
                        }
                  }
               
            x = 0 , y = 0;
            for(i = 1; i <= scc_cnt ; i++)
            {
                  if(!chu_du[i])  x += 1;
                  if(!ru_du[i])  y += 1;
            }
            x = x>y?x:y;
            if(scc_cnt == 1) {y = 1; x = 0;}
            printf("%d\n" , y);
              printf("%d\n" , x);
      }
      return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值