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;
}
posted @ 2016-11-21 21:04  Krew  阅读(185)  评论(0)    收藏  举报