CodeForces - 404C Restore Graph

Valera面临一项挑战,从顶点到所有其他顶点的最短距离和最大度数中恢复原始无向图。本篇详细介绍了问题背景、解决思路及C++实现代码,探讨了如何将距离排序并构建k叉树来连接边,确保图的正确性和可行性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Valera had an undirected connected graph without self-loops and multiple edges consisting of n vertices. The graph had an interesting property: there were at most k edges adjacent to each of its vertices. For convenience, we will assume that the graph vertices were indexed by integers from 1 to n.

One day Valera counted the shortest distances from one of the graph vertices to all other ones and wrote them out in array d. Thus, element d[i] of the array shows the shortest distance from the vertex Valera chose to vertex number i.

Then something irreparable terrible happened. Valera lost the initial graph. However, he still has the array d. Help him restore the lost graph.

Input
The first line contains two space-separated integers n and k (1 ≤ k < n ≤ 105). Number n shows the number of vertices in the original graph. Number k shows that at most k edges were adjacent to each vertex in the original graph.

The second line contains space-separated integers d[1], d[2], …, d[n] (0 ≤ d[i] < n). Number d[i] shows the shortest distance from the vertex Valera chose to the vertex number i.

Output
If Valera made a mistake in his notes and the required graph doesn’t exist, print in the first line number -1. Otherwise, in the first line print integer m (0 ≤ m ≤ 106) — the number of edges in the found graph.

In each of the next m lines print two space-separated integers ai and bi (1 ≤ ai, bi ≤ n; ai ≠ bi), denoting the edge that connects vertices with numbers ai and bi. The graph shouldn’t contain self-loops and multiple edges. If there are multiple possible answers, print any of them.

Examples
Input
3 2
0 1 1
Output
3
1 2
1 3
3 2
Input
4 2
2 0 1 3
Output
3
1 3
1 4
2 3
Input
3 1
0 0 0
Output
-1

题意:有一幅nnn个点的无向无环图(那不就是树吗=_=),边权全为111,现在只知道其中一个点到其他每个点的最短距离(与自己的距离是000)和每个点的最大度数kkk,请判断这样的图是否存在。存在则输出边数和每一条边,否则输出−1-11

思路:把距离按升序排序,然后当做是一棵k叉树,一层一层连边。如果第iii层所有的点的度数都到kkk了而第i+1i+1i+1层还有剩余的点,就输出−1-11
数据好坑啊,居然有一个点卡的是输入的距离没有000要输出−1-11

#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;

const int maxn = 100005;
int n, k;
int degree[maxn];
vector<pair<int,int> > G;
struct node
{
    int val, id;

    bool operator<(const node &a) const
    {
        return val < a.val;
    }
} d[maxn];

int main()
{
    bool flag = 0;
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; ++i)
    {
        scanf("%d", &d[i].val);
        d[i].id = i;
    }

    sort(d + 1, d + n + 1);

    if ((!d[1].val && !d[2].val) || d[1].val)//0的数量不为1时直接输出-1
    {
        printf("-1\n");
        return 0;
    }
    int fa = 1;
    for (int i = 2; i <= n; ++i)
    {
        while (d[i].val > d[fa].val + 1)
            ++fa;
        if (degree[d[fa].id] == k)
            ++fa;
        if (d[i].val != d[fa].val + 1)
        {
            flag = 1;
            break;
        }
        G.emplace_back(make_pair(d[fa].id,d[i].id));
        ++degree[d[fa].id];
        ++degree[d[i].id];
    }
    if (flag)
        printf("-1\n");
    else
    {
        printf("%d\n",(int)G.size());
        for (auto i:G)
            printf("%d %d\n",i.first,i.second);
    }
    return 0;
}
引用\[1\]中提到了一种树形动态规划的方法来解决CodeForces - 982C问题。在这个问题中,subtree指的是子连通块,而不是子树。为了使cnt_white - cnt_black尽可能大,可以使用两次树形动态规划来求解。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。如果ans\[u\]为正,则减去dp\[v\]就是树链所代表的子树的权值。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] 问题: CodeForces - 982C 树形DP是什么问题?如何解决? 回答: CodeForces - 982C是一个树形动态规划问题。在这个问题中,需要求解子连通块的最大权值和,使得cnt_white - cnt_black尽可能大。解决这个问题的方法是使用两次树形动态规划。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] #### 引用[.reference_title] - *1* *2* [CodeForces - 1324F Maximum White Subtree(树形dp)](https://blog.youkuaiyun.com/qq_45458915/article/details/104831678)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值