Codeforces 1082D Maximum Diameter Graph

Codeforces Tutorial

D. Maximum Diameter Graph

Problem Analysis

构造一个简单图,要求每个节点的度$ \le a_i$,并且图的直径最大。

构造过程分为两步:

  1. 用所有\(a_i \gt 1\)的节点构造一条直链\(L\)
  2. 将剩余的\(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)?

  • 生成满足某些要求的输出

这个构造问题的要求有以下三个:

  • 图的直径最大
  • 每个节点的度都有上限
  • 简单图

满足要求的顺序很重要。第一个最严格,所以优先第一个条件,满足直径最大。这样一来问题就迎刃而解了。

Reference

https://codeforces.com/blog/entry/63544

posted @ 2019-06-02 20:06  MalcolmMeng  阅读(119)  评论(0编辑  收藏  举报