Codeforces 1082D Maximum Diameter Graph(贪心构造)

Codeforces 1082D Maximum Diameter Graph(贪心构造)

题意

给n个点,每个点有连线度数上限,要求使得建立的无向联通图直径最长。

思路

直接贪心,把所有的度数大于1的点连成一条线,再把度数为1的点往上插就可以了,插不下就输出不行。

这么简单的题,题解都不用看几分钟就敲出来了,只能说当时以为自己退役了心情低落,说着佛系打CF结果真的佛系掉分了。

代码

#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
struct edge{
    int from;
    int to;
    int nxt;
    edge(int f,int t,int n):from(f),to(t),nxt(n){}
};
int egs[505];
vector<edge> edges;
void addedge(int f,int t){
    edges.emplace_back(f,t,egs[f]);
    egs[f]=edges.size()-1;
}
struct node
{
    int ind;
    int degree;
}a[505];
bool cmp(node aa,node bb){
    if(aa.degree!=bb.degree)
        return aa.degree>bb.degree;
    else
        return aa.ind<bb.ind;
}
int main() {
    int n;
    cin>>n;
    memset(egs,-1,sizeof egs);
    int counterone=0;
    int counternotone=0;
    for(int i=1;i<=n;i++){
        cin>>a[i].degree;
        if(a[i].degree>1){
            counternotone++;
        }
        else{
            counterone++;
        }
        a[i].ind=i;
    }
    sort(a+1,a+n+1,cmp);//按度数排序
    bool degreeone=false;
    bool imp=false;
    int endone=n;
    for(int i=2;i<=n;i++){
        if(!degreeone){
            addedge(a[i-1].ind,a[i].ind);
            if(a[i].degree==1){
                degreeone=true;//后面的点都是1了,但是第一个1的点先和最右边的点连,还算直径的
                endone=i;
            }
            a[i-1].degree--;
            a[i].degree--;
            if(a[i-1].degree<0 || a[i].degree<0){
                imp=true;
                break;
            }
        }
        else{
            bool succeeded=false;
            for(int j=1;j<endone;j++){//从最左边开始,见到空位就插。
                if(a[j].degree>=1){
                    addedge(a[j].ind,a[i].ind);
                    a[j].degree--;
                    a[i].degree--;
                    succeeded=true;
                    break;
                }
            }
            if(!succeeded){
                imp=true;//找不到能插点的地方,那就不可能
                break;
            }
        }
    }
    if(imp){
        cout<<"NO"<<endl;
    }
    else{
        if(counterone>=2){
            counternotone+=2;//度数为1的点最多有两个能加入直径。
        }
        else{
            counternotone+=counterone;
        }
        cout<<"YES "<<counternotone-1<<endl;
        cout<<edges.size()<<endl;
        for(int i=0;i<edges.size();i++){
            cout<<edges[i].from<<" "<<edges[i].to<<endl;
        }
    }
    return 0;
}

纯粹自己想出来的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值