【强连通分量缩点】poj 1236 Network of Schools

poj.org/problem?id=1236

【题意】

  • 给定一个有向图,求:
  • (1)至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点
  • (2)至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点

【思路】

  • (1)强连通分量缩点后形成一个有向无环图,只要选择入度为0的顶点,其他顶点都可以被到达
  • (2)等价于一个有向无环图加最少加多少条边能够变成一个强连通图,取出度为0的点的个数和入度为0的点的个数的max,因为出度为0的点要加一条出边,入度为0的点要加一条入边
  • (2)特判特殊情况:强连通分量只有一个,这时虽然入度为0和出度为0的点都是一个,但不需要加边

【AC】

  1 //#include<bits/stdc++.h>
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<string>
  5 #include<cstring>
  6 #include<algorithm>
  7 #include<cmath>
  8 using namespace std;
  9 typedef long long ll;
 10 int n;
 11 const int maxm=10002;
 12 const int maxn=1e2+2;
 13 struct edge
 14 {
 15     int to;
 16     int nxt;
 17 }e[maxm];
 18 int head[maxn],tot;
 19 int dfn[maxn],low[maxn],id;
 20 int S[maxn],top;
 21 int num,belong[maxn];
 22 bool vis[maxn];
 23 bool in[maxn];
 24 bool out[maxn];
 25 void init()
 26 {
 27     memset(head,-1,sizeof(head));
 28     tot=0;
 29     id=0;
 30     top=0;
 31     num=0;
 32     memset(dfn,0,sizeof(dfn));
 33     memset(low,0,sizeof(low));
 34     memset(S,0,sizeof(S));
 35     memset(vis,false,sizeof(vis));
 36     memset(belong,0,sizeof(belong));
 37     memset(in,false,sizeof(in));
 38     memset(out,false,sizeof(out));    
 39 }
 40 void addedge(int u,int v)
 41 {
 42     e[tot].to=v;
 43     e[tot].nxt=head[u];
 44     head[u]=tot++;
 45 }
 46 void tarjan(int u)
 47 {
 48     dfn[u]=low[u]=++id;
 49     S[++top]=u;
 50     vis[u]=true;
 51     for(int i=head[u];i!=-1;i=e[i].nxt)
 52     {
 53         int v=e[i].to;
 54         if(!dfn[v])
 55         {
 56             tarjan(v);
 57             low[u]=min(low[u],low[v]);
 58         }
 59         else if(vis[v]) low[u]=min(low[u],dfn[v]);
 60     }
 61     if(dfn[u]==low[u])
 62     {
 63         num++;
 64         while(1)
 65         {
 66             belong[S[top]]=num;
 67             vis[S[top]]=false;
 68             if(S[top--]==u) break;
 69         }
 70     }
 71     
 72 }
 73 
 74 int main()
 75 {
 76     while(~scanf("%d",&n))
 77     {
 78         init();
 79         for(int i=1;i<=n;i++)
 80         {
 81             int x;
 82             while(1)
 83             {
 84                 scanf("%d",&x);
 85                 if(x==0) break;
 86                 addedge(i,x);
 87             }
 88         }
 89         for(int i=1;i<=n;i++)
 90         {
 91             if(!dfn[i]) tarjan(i);
 92         }
 93         for(int u=1;u<=n;u++)
 94         {
 95             for(int i=head[u];i!=-1;i=e[i].nxt)
 96             {
 97                 int v=e[i].to;
 98                 if(belong[u]==belong[v]) continue;
 99                 in[belong[v]]=true;
100                 out[belong[u]]=true;
101             }
102         }
103         int ans1=0;
104         int ans2=0;
105         for(int i=1;i<=num;i++)
106         {
107             if(!in[i]) ans1++;
108             if(!out[i]) ans2++; 
109         }
110         int ans=max(ans1,ans2);
111         if(num==1) ans=0;
112         printf("%d\n%d\n",ans1,ans);
113     }
114     return 0;
115 }
View Code

【大佬博客】

www.cnblogs.com/kuangbin/archive/2011/08/07/2130277.html

解题思路:

        1. 求出所有强连通分量

        2. 每个强连通分量缩成一点,则形成一个有向无环图DAG

        3. DAG上面有多少个入度为0的顶点,问题1的答案就是多少

在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少

加边的方法:

要为每个入度为0的点添加入边,为每个出度为0的点添加出边

假定有 n 个入度为0的点,m个出度为0的点,如何加边?

把所有入度为0的点编号 0,1,2,3,4 ....N -1

每次为一个编号为i的入度0点可达的出度0点,添加一条出边,连到编号为(i+1)%N 的那个出度0点,

这需要加n条边

若 m <= n,则

加了这n条边后,已经没有入度0点,则问题解决,一共加了n条边

若 m > n,则还有m-n个入度0点,则从这些点以外任取一点,和这些点都连上边,即可,这还需加m-n条边。

所以,max(m,n)就是第二个问题的解

此外:当只有一个强连通分支的时候,就是缩点后只有一个点,虽然入度出度为0的都有一个,但是实际上不需要增加清单的项了,所以答案是1,0

转载于:https://www.cnblogs.com/itcsl/p/7441796.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值