您的位置:首页 > 产品设计 > UI/UE

hdu 2767 Proving Equivalences(强连通入门题)

2016-04-24 21:10 495 查看
/*************************************************
Proving Equivalences(hdu 2767)
强连通入门题
给个有向图,求至少加多少条边使得图是所有点都是强连通的
由a->b->c->a易知n个点至少要n条边,每个出度和入度都要大
于1。先求所有所有强连通分量,把每个强连通分量看成一个点
在找每个点的出度和入度,最后还差的出度和入度的最大值就是
答案。

*************************************************/

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;

const int mx=20005;
stack<int>s;
vector<int>g[mx];
int dfn[mx],low[mx];
int sccno[mx],vs[mx];
int cut_dfs,cut_scc;
int in[mx],out[mx];

void Init(int n)
{
cut_dfs=cut_scc=0;
memset(sccno,0,sizeof(sccno));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(vs,0,sizeof(vs));
for (int i=1;i<=n;i++) g[i].clear();
while (!s.empty()) s.pop();
}

void dfs(int u)
{

s.push(u);
low[u]=dfn[u]=++cut_dfs;
vs[u]=1;
for (int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if (!vs[v])
{
dfs(v);
low[u]=min(low[u],low[v]);
}
else if (!sccno[v]) low[u]=min(low[u],dfn[v]);///一定要加if (!sccno[v])
}

if (low[u]==dfn[u])
{
cut_scc++;
while (1)
{
int v=s.top();
s.pop();
sccno[v]=cut_scc;
if (v==u) break;
}
}
}

int main()
{
int t,n,m;
scanf("%d",&t);
while (t--)
{
scanf("%d%d",&n,&m);
Init(n);
int a,b;
while (m--)
{
scanf("%d%d",&a,&b);
g[a].push_back(b);
}
for (int i=1;i<=n;i++)
{
if (!dfn[i]) dfs(i);
}

if (cut_scc==1)
{
printf("0\n");
continue;
}
for (int i=1;i<=cut_scc;i++) in[i]=out[i]=1;
for (int i=1;i<=n;i++)
{
for (int j=0;j<g[i].size();j++)
{
int v=g[i][j];
if (sccno[i]!=sccno[v]) out[sccno[i]]=in[sccno[v]]=0;
}
}
a=b=0;
for (int i=1;i<=cut_scc;i++)
{
if (out[i]) a++;
if (in[i]) b++;
}
printf("%d\n",max(a,b));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: