LA 4287
题目链接:http://vjudge.net/problem/UVALive-4287
题目大意:给出一个有向图,要求添加最少的边,使得整个图联通
分析:
首先发现一个强连通分量肯定是强连通的,首先我们可以缩点,考虑得到的DAG,
首先对于出度为0的点,入度为0的点,它们肯定要连一条边,而且我们可以证明这样做一定存在一种方法可以使整个图强连通。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define sz(x) (int)(x.size())
using namespace std;
typedef long long LL;
const int maxn=20000+11;
int T,size,n,m,x,y,sc[maxn],ind[maxn],oud[maxn],a,b;
vector<int> G[maxn],rG[maxn],v;
bool vis[maxn];
void init()
{
v.clear();
rep(i,0,n) G[i].clear(),rG[i].clear();
memset(ind,0,sizeof(ind));
memset(oud,0,sizeof(oud));
}
void DFS1(int k)
{
vis[k]=1;
rep(i,0,sz(G[k])-1) if (!vis[G[k][i]]) DFS1(G[k][i]);
v.push_back(k);
}
void DFS2(int k,int num)
{
vis[k]=1,sc[k]=num;
rep(i,0,sz(rG[k])-1) if (!vis[rG[k][i]]) DFS2(rG[k][i],num);
}
int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
init();
rep(i,1,m)
{
scanf("%d%d",&x,&y);
G[x].push_back(y);
rG[y].push_back(x);
}
memset(vis,0,sizeof(vis));
rep(i,1,n) if (!vis[i]) DFS1(i);
memset(vis,0,sizeof(vis));
size=0;
dep(i,sz(v)-1,0) if (!vis[v[i]]) DFS2(v[i],++size);
rep(i,1,n)
rep(j,0,sz(G[i])-1)
{
x=G[i][j];
if (sc[x]!=sc[i]) ind[sc[x]]++,oud[sc[i]]++;
}
a=0,b=0;
rep(i,1,size)
{
if (ind[i]==0) a++;
if (oud[i]==0) b++;
}
if (size==1) printf("%d\n",0); else printf("%d\n",max(a,b));
}
return 0;
}

浙公网安备 33010602011771号