(intermediate)DFS (边-双连通) UVA 10972 RevolC FaeLoN

Problem I

RevolC FaeLoN

Hopefully, you can remember Koorosh from one of the previous problems. Fortunately, Koorosh has solved Basm’s problem without your help! Now, he is a high-ranked advisor of Basm.

 As usual, Basm has conquered a new territory, called RevolC FaeLoN. In order to make the people of RevolC FaeLoN satisfied, he wants to solve one of their basic problems. The RevolC FaeLoN has a high annual   rate of camel accidents and Basm wants to make the roads of this territory unidirectional in order to reduce the accident rate.

He wants to do this task in such a way that each city has at least one path to every other city. Now, Basm has asked Koorosh to find the minimum number of unidirectional roads which need to be constructed (in addition to the task of making the existing roads unidirectional) in order for every city to be reachable from every other city. Note that the original graph representing the territory is simple but during the road construction process, extra roads can be constructed between two cities that have already been connected to each other by a road.

 

The Input

Input consists of several test-cases. Each test case begins with two numbers  and m which are the number of cities and roads of RevolC FaeLoN respectively. The next m lines, each contain two integers , indicating that there is a road between u and v. The input is terminated by end of file.

 

The Output

For each test-case, print the minimum number of roads that should be constructed to make Basm’s decision possible.

 

Sample Input

3 2

1 2

2 3

10 11

1 2

2 3

3 1

3 7

4 5

5 6

6 4

7 9

6 3

9 8

7 8

 

Sample Output

1

2


题意:给出一个无向图,然后要把所有的边改成有向边,问最少需要加多少条边使得整个图强连通。
思路:先求出边-双连通分量,每个边-双连通分量我们总有办法构成强连通的,那么最后简化后的图就是一个森林,
然后我们要在上面加边,每一次我们能消去两个度数为1的点,那么如果有孤立的点怎么办,把他们连到树上度数为1的点,那么树的度数为1的点不变。还是每次消去2个度数为1的点。是森林的话同理的,把树之间连起来,也能消去2个度数为1的点。

代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 1000+5;
vector<int> G[maxn];
vector<int>  DAG[maxn];
vector<int> bcc[maxn];
int n , m , dfs_clock , cnt , pre[maxn] , bccno[maxn] , bcc_cnt;
int deg[maxn];
bool vis[maxn];
bool is_bridge[maxn][maxn];

void input()
{
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);
G[v].push_back(u);
}
}

int dfs1(int u,int fa)
{
int lowu = pre[u] = ++dfs_clock;
for (int i = 0 ; i < G[u].size() ; ++i)
{
int v = G[u][i];
if (v==fa) continue;
if (!pre[v])
{
int lowv = dfs1(v,u);
lowu = min(lowu,lowv);
if (lowv > pre[u]) is_bridge[u][v] = is_bridge[v][u] = true;
} else if (lowu > pre[v])
lowu = pre[v];
}
return lowu;
}

void dfs2(int u)
{
if (vis[u]) return;
vis[u] = true;
bccno[u] = bcc_cnt;
bcc[bcc_cnt].push_back(u);
for (int i = 0 ; i < G[u].size() ; ++i) 
{
int v = G[u][i];
if (is_bridge[u][v]) continue;
dfs2(G[u][i]);
}
}

void find_bcc()
{
memset(pre,0,sizeof(pre));
memset(bccno,0,sizeof(bccno));
memset(is_bridge,0,sizeof(is_bridge));
dfs_clock = bcc_cnt = 0;
cnt = 0;
for (int i = 1 ; i <= n ; ++i) 
if (!pre[i]) { ++cnt; dfs1(i,-1); }
memset(vis,0,sizeof(vis));
for (int i = 1 ; i <= n ; ++i) if (!vis[i]) 
{
++bcc_cnt;
bcc[bcc_cnt].clear();
dfs2(i);
}
for (int i = 1 ; i <= bcc_cnt ; ++i) DAG[i].clear();
memset(vis,0,sizeof(vis));
memset(deg,0,sizeof(deg));
for (int i = 1 ; i <= bcc_cnt ; ++i)
{
vis[i] = true;
for (int j = 0 ; j < bcc[i].size() ; ++j)
{
int u = bcc[i][j];
for (int k = 0 ; k < G[u].size() ; ++k)
{
int v = G[u][k];
if (vis[bccno[v]]) continue;
vis[bccno[v]] = true;
++deg[bccno[u]];
++deg[bccno[v]];
DAG[bccno[u]].push_back(bccno[v]);
DAG[bccno[v]].push_back(bccno[u]);
}
}
for (int j = i+1 ; j <= bcc_cnt ; ++j) vis[j] = false;
}
}

void solve()
{
int ans = 0;
find_bcc();
if (bcc_cnt==1)
{
cout << 0 << endl;
return;
}
for (int i = 1 ; i <= bcc_cnt ; ++i)
{
if (deg[i]==1) ++ans;
else if (deg[i]==0) ans += 2;
}
cout << (ans+1)/2 << endl;
}

int main()
{
while (scanf("%d%d",&n,&m)==2)
{
input();
solve();
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值