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

UVa 12167 & HDU 2767 强连通分量 Proving Equivalences

2015-08-12 11:20 471 查看
题意:给出一个有向图,问最少添加几条有向边使得原图强连通。

解法:求出SCC后缩点,统计一下出度为0的点和入度为0的点,二者取最大值就是答案。

还有个特殊情况就是本身就是强连通的话,答案就是0.

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

const int maxn = 20000 + 10;

int n, m;

vector<int> G[maxn];

stack<int> S;
int pre[maxn], low[maxn], sccno[maxn];
int dfs_clock, scc_cnt;

void dfs(int u, int fa)
{
low[u] = pre[u] = ++dfs_clock;
S.push(u);

for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if(!pre[v])
{
dfs(v, u);
low[u] = min(low[u], low[v]);
}
else if(!sccno[v]) low[u] = min(low[u], pre[v]);
}

if(pre[u] == low[u])
{
scc_cnt++;
for(;;)
{
int x = S.top(); S.pop();
sccno[x] = scc_cnt;
if(x == u) break;
}
}
}

void find_scc()
{
memset(pre, 0, sizeof(pre));
memset(sccno, 0, sizeof(sccno));
dfs_clock = scc_cnt = 0;
for(int i = 1; i <= n; i++) if(!pre[i]) dfs(i, 0);
}

int in[maxn], out[maxn];

int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) G[i].clear();
while(m--)
{
int u, v; scanf("%d%d", &u, &v);
G[u].push_back(v);
}

find_scc();

if(scc_cnt == 1) { puts("0"); continue; }

memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
for(int i = 1; i <= n; i++)
for(int j = 0; j < G[i].size(); j++)
{
int u = sccno[i], v = sccno[G[i][j]];
if(u != v) { out[u]++; in[v]++; }
}

int hehe = 0, haha = 0;
for(int i = 1; i <= scc_cnt; i++)
{
if(!in[i]) hehe++;
if(!out[i]) haha++;
}
printf("%d\n", max(hehe, haha));
}

return 0;
}


代码君
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: