Gym101630C Connections
题目大意:
给出一个\(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\n",edge[i].first,edge[i].second); 58 has--; 59 } 60 } 61 } 62 return 0; 63 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”