NC51269 Network of Schools
题目:
给你一张有向图,问最少要加几条边才能使得图上的点都属于同一个强连通分量
题解:

加边变成强连通分量
缩点之后,入度为0的点和出度为0的点两两连边,多随便一连——答案就是max(入度为0的点数,出度为0的点数)
处理后:
代码:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
return s*w;
}
const int maxn=1e6+9;
vector<int>edge[maxn];
int low[maxn],dfn[maxn];
int vis[maxn];
int cnt=0;
stack<int>s;
int num1,num2;
int block;
int color[maxn];
int in[maxn],out[maxn];
void tarjan(int u)
{
low[u]=dfn[u]=++cnt;
vis[u]=1;
s.push(u);
for(int i=0;i<edge[u].size();i++)
{
int v=edge[u][i];
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v])low[u]=min(low[u],dfn[v]);
}
int x;
if(dfn[u]==low[u])
{
block++;
do
{
x=s.top();
s.pop();
vis[x]=0;
color[x]=block;
}while(x!=u);
}
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
int x;
while(cin>>x)
{
if(x==0)break;
edge[i].push_back(x);
}
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])tarjan(i);
}
for(int u=1;u<=n;u++)
{
for(int i=0;i<edge[u].size();i++)
{
int x=color[u];
int y=color[edge[u][i]];
if(x!=y)
{
out[x]++;
in[y]++;
}
}
}
for(int i=1;i<=block;i++)
{
if(in[i]==0)num1++;
if(out[i]==0)num2++;
}
if(block==1)cout<<"1"<<endl<<"0"<<endl;
else printf("%d\n%d",num1,max(num1,num2));
}

京公网安备 11010502036488号