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$ integers $a_1, a_2, \dots, a_n$ construct a connected undirected graph of $n$ vertices such that:

  • the graph contains no self-loops and no multiple edges;
  • the degree $d_i$ of the $i$-th vertex doesn't exceed $a_i$ (i.e. $d_i \le a_i$);
  • the diameter of the graph is maximum possible.

Output the resulting graph or report that no solution exists.


题意

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


思路

  判断是否能构造一个连通图,如果可以的话,将所有度数大于$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;
}
最后修改:2018 年 12 月 01 日
谢谢老板!