有向图加边成强连通图(tarjan缩点)

https://www.luogu.com.cn/problem/P2746

该题简化一下就是下面两个问题:
1、最少要给多少个点发消息,才能使得所有的点都收到消息(消息可以随边传递)
2、最少需要多少条边才能使得图变成强连通图
首先我们先使用tarjan算法求出图中的强连通分量,对于一个强连通分量,可以当做一个点来考虑,所以我们可以缩点,然后得到DAG图。
那么对于第一个问,即是入度为0的点有多少个,因为入度为0的点无法收到消息。
对于第二问,只要加max(s1,s2)条边,就能使得DAG变成强连通图, s1表示入度为0的点的个数,s2表示出度为0的点的个数。设s1 > s2, 那么首先加s2条边,这s2条边连接的是入度为0和出度为0的点,然后剩下s1-s2个入度为0的点, 那么随便加s1-s2条边即可。
当然有一个特殊情况需要特判一下,当整个图原本就是一个强连通图时,缩完点之后,s1,s2都是1,但是本身不需要加边就是一个强连通图。``
AC代码:

#include<iostream>
#include<cstdio>
#include<stack>
#include<cstring>
using namespace std;
int T;
int head[110],a[10010],b[10010],dfn[110],low[110],scc[110],rd[110],cd[110],f[110][110];
bool vis[110];
struct edge{
 int to,w,next;
}e[10010];
int cnt;
void add(int u,int v,int w){
 e[++cnt].to =v;
 e[cnt].w =w;
 e[cnt].next =head[u];
 head[u]=cnt;
}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
int tot,scnt=0;
stack<int>s;
void tarjan(int u){
 vis[u]=1;
 s.push(u);
 dfn[u]=low[u]=++tot;
 for(int i=head[u];i;i=e[i].next ){
  int v=e[i].to ;
  if(!dfn[v]){
   tarjan(v);
   low[u]=min(low[u],low[v]);
  }
  else if(vis[v])
  low[u]=min(low[u],dfn[v]);
 }
 if(low[u]==dfn[u]){
  scnt++;
  int x;
  do
  {
   x=s.top();s.pop();
   vis[x]=0;
   scc[x]=scnt; 
  }while(x!=u);
 }
}
int main(){
 int n;
 cin>>n;
 int m=0;
 for(int u=1;u<=n;u++){
  int v;
  while(cin>>v&&v>0){
   m++;
   a[m]=u,b[m]=v;
   add(u,v,1);
  }
 }
 for(int i=1;i<=n;i++){
  if(!dfn[i])tarjan(i);
 }
 int ansa=0;
 int ansb=0;
 int sum=0;
 if(scnt==1){
  ansa=1,ansb=0;
 }
 else{
  for(int i=1;i<=m;i++){
   if(scc[a[i]]!=scc[b[i]]&&!f[scc[a[i]]][scc[b[i]]]){
    cd[scc[a[i]]]++;
    rd[scc[b[i]]]++; 
    f[scc[a[i]]][scc[b[i]]]=1;
   }
  }
  for(int i=1;i<=scnt;i++){
   if(rd[i]==0)ansa++;
   if(cd[i]==0)sum++;
  }
  ansb=max(ansa,sum);
 }
 cout<<ansa<<endl;
 cout<<ansb<<endl;
 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值