Codeforces Tutorial
D. Maximum Diameter Graph
Problem Analysis
构造一个简单图,要求每个节点的度$ le a_i$,并且图的直径最大。
构造过程分为两步:
- 用所有(a_i gt 1)的节点构造一条直链(L)
- 将剩余的(a_i = 1)的节点从(L)两端向中间添加分支
最后的结果就是一棵树
所以要求
[sum_{i=1}^{n}a_i ge 2(n-1)
]
Acepted Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<cmath>
#include<map>
#include<istream>
#include<cassert>
#include<set>
#define DEBUG(x) cout<<#x<<" = "<<x<<endl
#define DEBUG2(x,y) cout<<#x<<" = "<<x<<" , "
<<#y<<" = "<<y<<endl
using namespace std;
typedef long long ll;
const int MAXN=600;
int n;
int a[MAXN];
int main()
{
// freopen("in.txt","r",stdin);
cin>>n;
int sum=0;
vector<int>ones;
for(int ii=1;ii<=n ;ii++ ){
cin>>a[ii];
sum+=a[ii];
if(a[ii]==1){
ones.push_back(ii);
a[ii]=0;
}
}
if(sum<2*n-2){
cout<<"NO";
return 0;
}
int ans=n-ones.size()-1+min(2,(int)ones.size());
cout<<"YES "<<ans<<endl<<n-1<<endl;
int lst=-1;
if(!ones.empty()){
lst=ones.back();
ones.pop_back();
}
for(int ii=1;ii<=n ;ii++ ){
if(a[ii]>1){
if(lst!=-1){
a[ii]--,a[lst]--;
cout<<lst<<" "<<ii<<endl;
}
lst=ii;
}
}
for(int ii=n;ii>=1 ;ii-- ){
while (!ones.empty()&&a[ii]>0){
a[ii]--;
cout<<ones.back()<<" "<<ii<<endl;
ones.pop_back();
}
}
}
Wrong Answer Cases
What I Learn
什么是构造(construct)?
- 生成满足某些要求的输出
这个构造问题的要求有以下三个:
- 图的直径最大
- 每个节点的度都有上限
- 简单图
满足要求的顺序很重要。第一个最严格,所以优先第一个条件,满足直径最大。这样一来问题就迎刃而解了。