Educational Codeforces Round 55 (Rated for Div. 2):D. Maximum Diameter Graph
D. Maximum Diameter Graph
题目链接:https://codeforces.com/contest/1082/problem/D
题意:
给出n个点的最大入度数,要求添加边构成一个无环无向无重边的图,并且最大化图中的最短路径。
题解:
要求最短路径最大,我们会想到把每一个允许入度可以大于1的点先连起来,形成一个”链“,当前肯定满足条件,并且两端点的最短路径长度是所有情况中最大的。
然后对于入度为1的点,先尽量考虑放在链的两端,然后再在中间随便插入。
代码如下:
先附上自己用邻接矩阵存储的丑代码。。。代码思路比较直接:
#include <bits/stdc++.h> using namespace std; const int N = 505; int Map[N][N],vis[N],a[N]; int n; int main(){ scanf("%d",&n); int cnt = 0,tot = 0,st = 0; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); if(a[i]==1) cnt++; else st=i; } vis[st]=1;bool flag=false; int end=st; for(int i=st;;i=end){ if(flag) break; int tmp=0; for(int j=1;j<=n;j++){ if(a[j]>1 && !vis[j]){ tmp++; Map[i][j]=Map[j][i]=1; vis[j]=1; a[i]--;a[j]--; end=j; break; } } if(!tmp) flag=true; } int tmp = 0; for(int i=1;i<=n;i++) if(vis[i]) tot+=a[i],tmp++; if(cnt>tot){ cout<<"NO"; return 0; } int ans,edges=tmp-1; if(cnt>1) ans=edges+2; else if(cnt==1) ans=edges+1; else ans=edges; cout<<"YES"<<" "<<ans<<endl; if(cnt){ cnt--; for(int i=1;i<=n;i++) if(!vis[i]){ vis[i]=Map[i][st]=Map[st][i]=1; edges++; a[st]--;a[i]--; break ; } if(cnt){ cnt--; for(int i=1;i<=n;i++) if(!vis[i]){ vis[i]=Map[i][end]=Map[end][i]=1; edges++; a[end]--;a[i]--; break; } } if(cnt){ for(int i=n;i>=1;i--) if(!vis[i]){ vis[i]=1; for(int j=1;j<=n;j++){ if(a[j] && vis[j] &&j!=i){ edges++; Map[j][i]=Map[i][j]=1; a[j]--;a[i]--; break; } } } } } cout<<edges<<endl; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(Map[i][j]) printf("%d %d\n",i,j); return 0; }
再来一个O(N)的算法,注意一下代码的细节,直接像链一样连边:
#include <bits/stdc++.h> using namespace std; const int N = 505; int a[N]; int n,sum; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum+=a[i]; if(sum<2*(n-1)){ cout<<"NO";return 0; } vector <int> ones; for(int i=1;i<=n;i++){ if(a[i]==1) a[i]=0 , ones.push_back(i); } int t=ones.size(); printf("YES %d\n%d\n",n-t-1+min(t,2),n-1); int st=0; if(!ones.empty()){ st=ones.back(); ones.pop_back(); } for(int i=1;i<=n;i++){//从起点开始添边形成一个链 if(a[i]>1){ if(st){ a[st]--;a[i]--; printf("%d %d\n",st,i); } st=i; } } for(int i=n;i>=1;i--){ // 从尾开始添加(在链上) while(a[i]>0 && !ones.empty()){ a[i]--; int now1 = ones.back();ones.pop_back(); printf("%d %d\n",i,now1); } } return 0; }
重要的是自信,一旦有了自信,人就会赢得一切。