Codeforces 1082D - Maximum Diameter Graph - 贪心

80 篇文章 0 订阅
29 篇文章 1 订阅

Codeforces 1082D - Maximum Diameter Graph - 贪心

题解链接

https://lucien.ink


题目链接

https://codeforces.com/contest/1082/problem/D


题目

Graph constructive problems are back! This time the graph you are asked to build should match the following properties.

The graph is connected if and only if there exists a path between every pair of vertices.

The diameter (aka "longest shortest path") of a connected undirected graph is the maximum number of edges in the shortest path between any pair of its vertices.

The degree of a vertex is the number of edges incident to it.

Given a sequence of n n n integers a 1 , a 2 , … , a n a_1, a_2, \dots, a_n a1,a2,,an construct a connected undirected graph of n n n vertices such that:

  • the graph contains no self-loops and no multiple edges;
  • the degree d i d_i di of the i i i-th vertex doesn’t exceed a i a_i ai (i.e. d i ≤ a i d_i \le a_i diai);
  • the diameter of the graph is maximum possible.

Output the resulting graph or report that no solution exists.


题意

  有 n n n个点,第 i i i个点的度最大为 a i a_i ai,问将这 n n n个点连通后图的最大直径是多少。


思路

  判断是否能构造一个连通图,如果可以的话,将所有度数大于 1 1 1的点连成一条线,剩下度为一点尽量连一下最左边和最右边的点,然后随便连即可。可以证明,这样贪心一定是最优的。


实现

#include <bits/stdc++.h>
const int maxn = 507;
int n, sum, cnt, ans;
struct Node {
    int deg, index;
} node[maxn];
std::queue<int> que;
struct Edge {
    int u, v;
} edge[maxn << 1];
int main() {
#ifdef AC
    freopen("../in", "r", stdin);
#endif
    scanf("%d", &n);
    int len = 0;
    for (int i = 1, buf; i <= n; i++) {
        scanf("%d", &buf);
        sum += buf;
        if (buf == 1) que.push(i);
        else node[++len] = {buf, i};
    }
    if (sum < (n - 1) * 2) return 0 * puts("NO");
    for (int i = 1; i < len; i++) {
        edge[++cnt] = {node[i].index, node[i + 1].index};
        node[i].deg--;
        node[i + 1].deg--;
        ans++;
    }
    if (!que.empty()) {
        int cur = que.front();
        que.pop();
        edge[++cnt] = {cur, node[1].index};
        node[1].deg--;
        ans++;
    }
    if (!que.empty()) {
        int cur = que.front();
        que.pop();
        edge[++cnt] = {cur, node[len].index};
        node[len].deg--;
        ans++;
    }
    while (!que.empty()) {
        int cur = que.front();
        que.pop();
        for (int i = 1; i <= len; i++) {
            if (node[i].deg > 0) {
                edge[++cnt] = {node[i].index, cur};
                node[i].deg--;
                break;
            }
        }
    }
    printf("YES %d\n", ans);
    printf("%d\n", cnt);
    for (int i = 1; i <= cnt; i++) printf("%d %d\n", edge[i].u, edge[i].v);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值