题目大意:
给出一个(n)个点(m)条边的有向图,无自环无重边。要求把这个图进行删边,直到只剩下(2n)条边,使得图中每个点都可以相互连通。
知识点: DFS
解题思路:
从点(1)出发,进行一次(DFS),把所有的点都访问一次,标记经过的边,这些边保证了点(1)能到所有的点。再额外建一个图(图中所有的边都是原图的边的反向),再进行一次与上面类似的DFS操作:从点(1)出发,把所有的点都访问一次,标记经过的边,这些边保证了所有的点都能到点(1)。两次(DFS)最多标记(2n-2)条边,并保证了所有点都能到点(1),点(1)能到所有点,如此所有点都能到所有点,每个点都可以相互连通。被标记的边就是必需的,删除其他边直到只剩下(2n)条边即可。
AC代码:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 typedef pair<int,int> P; 5 const int maxn=100000+5; 6 vector<int>G[maxn],tG[maxn]; 7 P edge[maxn]; 8 map<P,int> used; 9 int n; 10 bool vis[maxn]; 11 void init(){ 12 for(int i=1;i<=n;i++) vis[i]=false; 13 } 14 void dfs1(int rt){ 15 for(int i=0;i<G[rt].size();i++){ 16 if(!vis[G[rt][i]]){ 17 vis[G[rt][i]]=true; 18 dfs1(G[rt][i]); 19 used[make_pair(rt,G[rt][i])]++; 20 } 21 } 22 } 23 void dfs2(int rt){ 24 for(int i=0;i<tG[rt].size();i++){ 25 if(!vis[tG[rt][i]]){ 26 vis[tG[rt][i]]=true; 27 dfs2(tG[rt][i]); 28 used[make_pair(tG[rt][i],rt)]++; 29 } 30 } 31 } 32 int main(){ 33 int t; 34 scanf("%d",&t); 35 while(t--){ 36 int m,u,v; 37 scanf("%d%d",&n,&m); 38 used.clear(); 39 for(int i=1;i<=n;i++){ 40 G[i].clear(); 41 tG[i].clear(); 42 } 43 for(int i=1;i<=m;i++){ 44 scanf("%d%d",&u,&v); 45 G[u].push_back(v),tG[v].push_back(u); 46 edge[i]=make_pair(u,v); 47 } 48 init(); 49 vis[1]=true; 50 dfs1(1); 51 init(); 52 vis[1]=true; 53 dfs2(1); 54 int has=m; 55 for(int i=1;i<=m&&has>2*n;i++){ 56 if(used[edge[i]]==0){ 57 printf("%d %d ",edge[i].first,edge[i].second); 58 has--; 59 } 60 } 61 } 62 return 0; 63 }