天天看点

Gym - 101630 C - Connections 两次dfs强连通图

codeforces的链接:Gym - 101630 C - Connections

牛客的链接:https://ac.nowcoder.com/acm/problem/54385

题目描述

Gym - 101630 C - Connections 两次dfs强连通图

输入描述

Gym - 101630 C - Connections 两次dfs强连通图

输出描述

Gym - 101630 C - Connections 两次dfs强连通图

样例

Gym - 101630 C - Connections 两次dfs强连通图

题意

一个有向图,有n个点,有m条边,现在需要你删除m-2n条边,使得剩下的2n条边依旧可以组成强连通图,且把删除的边输出

题解

正反向建图且对各个边进行相同的下标标记,默认1为起始位置,分别在正反图进行dfs遍历,并判断是否经历过该点和该边,这就可以保证有一个强连通图了,故可以直接for遍历选出前n-2*m个没有被遍历过的边了。

#pragma GCC optimize(2)
#include<bits/stdc++.h> 
using namespace std;
#define ll long long
#define endl "\n"
const int MAX=1e6+7;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
struct node{
	int to,id;
};
bool vis[MAX],check[MAX];
vector<pair<int,int>>edge; 
vector<node>g[MAX],g2[MAX];
void dfs1(int u){
	vis[u]=1;
	for(auto it: g[u]){
		int v=it.to, id=it.id;
		if(!vis[v]){
			check[id]=1;
			dfs1(v);
		}
	}
}
void dfs2(int u){
	vis[u]=1;
	for(auto it:g2[u]){
		int v=it.to,id=it.id;
		if(!vis[v]){
			check[id]=1;
			dfs2(v);
		} 
	}
}
int main(){
    ios_base::sync_with_stdio(0);cin.tie(0),cout.tie(0);
	int t;cin>>t;
	while(t--){
		int n,m;cin>>n>>m;
		edge.clear();
        for(int i=0;i<=m;i++)vis[i]=check[i]=0;
		for(int i=0;i<=n;i++)g[i].clear(),g2[i].clear();
		for(int i=0;i<m;i++){
			int u,v;cin>>u>>v;
			g[u].push_back({v,i}); 
			g2[v].push_back({u,i});
			edge.push_back({u,v});
		}
		dfs1(1);
        for(int i=0;i<=m;i++)vis[i]=0;  //反向边遍历需清0
		dfs2(1);
		for(int i=0,j=0;i<m&&j<m-2*n;i++){
			if(!check[i]){
				j++;
				cout<<edge[i].first<<" "<<edge[i].second<<endl;
			}
		}
	}
   return 0;
} 
           

继续阅读