Codeforce Round #544(Div3)
F1:
给一个无向图,求它的一棵生成树,使得生成树度数最大的点的度数尽可能大
题解:
找到度数最大的点,把与这个点相连的所有边加入,然后遍历一遍所有的边,建一棵生成树就好了
错误想法:把边排序,使得两端点度数最大值大的边在前面,这样前面的边就是度数最大的了(并不)
原因:如果度数最大的点有两个或者更多,就会有这种情况:
假设 a,b两点度数最大且相同,那么排序的时候,a,b都在前面,但是a不一定在b前面,同样,b也不一定在a前面,这就会造成:a用了一般,b用了一半,但是此时已经构成了一棵生成树,但是这棵树的度数最大的点显然小于degree[a]=degree[b]
(upd:其实这么做也可以,排序的时候加个下面这种东西:
1 bool cmp(pii a,pii b) 2 { 3 if(max(deg[a.first],deg[a.second]) == max(deg[b.first],deg[b.second])) return min(a.first,a.second) <min(b.first,b.second); 4 return max(deg[a.first],deg[a.second]) > max(deg[b.first],deg[b.second]); 5 }
不加第三行会出现上述错误,添加后可AC)(不过这也....太丑了)
代码如下:
1 #include<bits/stdc++.h> 2 #define pii pair<int,int> 3 using namespace std; 4 const int maxn=2e5+5; 5 vector<int> G[maxn]; 6 int parent[maxn]; 7 int deg[maxn]; 8 int n,m; 9 int find(int x) 10 { 11 return x==parent[x]?x:parent[x]=find(parent[x]); 12 } 13 int main() 14 { 15 ios::sync_with_stdio(0); 16 cin>>n>>m; 17 for(int i=1;i<=n;++i) parent[i]=i; 18 for(int i=1;i<=m;++i) 19 { 20 int a,b; cin>>a>>b; 21 ++deg[a],++deg[b]; 22 G[a].push_back(b); 23 G[b].push_back(a); 24 } 25 int sta,maxx=0; 26 for(int i=1;i<=n;++i) 27 { 28 if(deg[i]>=maxx) sta=i,maxx=deg[i]; 29 } 30 int cnt=0; 31 for(int i=0;i<G[sta].size();++i) 32 { 33 ++cnt; 34 int to=G[sta][i]; 35 parent[to]=sta; 36 printf("%d %d\n",sta,to); 37 } 38 for(int i=1;i<=n;++i) 39 { 40 if(i==sta) continue; 41 for(int j=0;j<G[i].size();++j) 42 { 43 if(cnt==n-1) break; 44 int to=G[i][j]; 45 int a=find(i),b=find(to); 46 if(a==b) continue; 47 else 48 { 49 ++cnt; 50 parent[b]=a; 51 printf("%d %d\n",i,to); 52 } 53 } 54 } 55 }