POJ 3177 Redundant Paths && POJ 3352
Edge-Double Connected Components, Graph Theory
meaning of the title
These two questions are similar. They all give you an undirected graph of China Unicom. Ask how many edges you need to add at least so that there are two paths between any two points in the graph.
For bi-connected components, please refer to discrete mathematical graph theory.
The difference is that 3177 has multiple sides. 3352 guarantees that the input has no heavy edges. And 3177 backstage test data answer seems to think that the heavy side is only one side.
For example, there are three points and four sides, two sides between points 1 and 2, and two sides between points 2 and 3. In theory, there are two paths between each two points, without adding edges, output 0. The code does not need to be de-duplicated (see the code for details), but the code without de-duplicate can be WA, which needs to be added to de-duplicate. Equivalent to 12 between one side, 23 between one side, output 1.
thinking
Actually, the code of double connected component is similar to that of targan's strong connected component. The idea is the same. Just add a little modification.
With the targan shrinkage point, the dual-link block is deflated. Then the new map is counted (because the undirected connection map, so all the points are at least 1), just need to connect all the points in 1, need (sum+1) / 2 edges.
Tagan double connected component:
struct Targan//Finding the Component of Side-to-Side Double Connection
{
vector<int> G[MAXN];
int pre[MAXN], lowlink[MAXN], sccno[MAXN], dfs_clock, scc_cnt;
stack<int> S;
void Addedge(int u, int v)
{
//This for loop is to be rewritten
for(int i=0;i<G[u].size();i++)
{
if(G[u][i]==v) return;
}
G[u].push_back(v);
G[v].push_back(u);
}
void init()
{
while(!S.empty()) S.pop();
for(int i=0;i<MAXN;i++) G[i].clear();
}
void dfs(int u, int fa)//Directionless graph, prevent searching his father, add a fa judgment
{
pre[u]=lowlink[u]=++dfs_clock;
S.push(u);
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(v==fa) continue;//Directionless graph, prevent searching his father, add a fa judgment
//There are only two kinds of undirected graph: tree edge and reverse edge. if corresponds to tree edge, continue searching, else corresponds to reverse edge, update low and count double connected blocks.
if(!pre[v])
{
dfs(v, u);
lowlink[u]=min(lowlink[u], lowlink[v]);
}
else
{
lowlink[u]=min(lowlink[u], pre[v]);
}
}
if(lowlink[u]==pre[u])
{
scc_cnt++;
while(1)
{
int x=S.top();S.pop();
sccno[x]=scc_cnt;
if(x==u) break;
}
}
}
void find_scc(int n)
{
dfs_clock=scc_cnt=0;
M(sccno, 0);M(pre, 0);M(lowlink, 0);
for(int i=1;i<=n;i++)
{
if(!pre[i]) dfs(i, -1);
}
}
}targan;
Code
Write a night wa on the double side.
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#define _ ios_base::sync_with_stdio(0),cin.tie(0)
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=10005;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
struct Targan//Finding the Component of Side-to-Side Double Connection
{
vector<int> G[MAXN];
int pre[MAXN], lowlink[MAXN], sccno[MAXN], dfs_clock, scc_cnt;
stack<int> S;
void Addedge(int u, int v)
{
//This for loop is to be rewritten
for(int i=0;i<G[u].size();i++)
{
if(G[u][i]==v) return;
}
G[u].push_back(v);
G[v].push_back(u);
}
void init()
{
while(!S.empty()) S.pop();
for(int i=0;i<MAXN;i++) G[i].clear();
}
void dfs(int u, int fa)
{
pre[u]=lowlink[u]=++dfs_clock;
S.push(u);
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(v==fa) continue;
if(!pre[v])
{
dfs(v, u);
lowlink[u]=min(lowlink[u], lowlink[v]);
}
else
{
lowlink[u]=min(lowlink[u], pre[v]);
}
}
if(lowlink[u]==pre[u])
{
scc_cnt++;
while(1)
{
int x=S.top();S.pop();
sccno[x]=scc_cnt;
if(x==u) break;
}
}
}
void find_scc(int n)
{
dfs_clock=scc_cnt=0;
M(sccno, 0);M(pre, 0);M(lowlink, 0);
for(int i=1;i<=n;i++)
{
if(!pre[i]) dfs(i, -1);
}
}
}targan;
int indegree[MAXN];
int main()
{
_;
int n;
while(cin>>n)
{
int m;cin>>m;
targan.init();
M(indegree, 0);
while(m--)
{
int a, b;cin>>a>>b;
targan.Addedge(a, b);
}
targan.find_scc(n);
for(int i=1;i<=n;i++)
{
for(int j=0;j<targan.G[i].size();j++)
{
int to=targan.G[i][j];
if(targan.sccno[i]!=targan.sccno[to])
{
indegree[targan.sccno[to]]++;
}
}
}
int sum=0;
for(int i=1;i<=targan.scc_cnt;i++)
{
if(indegree[i]==1) sum++;
}
cout<<(sum+1)/2<<endl;
}
return 0;
}