zoukankan      html  css  js  c++  java
  • Codeforces Round #237 (Div. 2) C. Restore Graph(水构造)

    题目大意

    一个含有 n 个顶点的无向图,顶点编号为 1~n。给出一个距离数组:d[i] 表示顶点 i 距离图中某个定点的最短距离。这个图有个限制:每个点的度不能超过 k

    现在,请构造一个这样的无向图,要求不能有自环,重边,且满足距离数组和度数限制,输出图中的边;如果无解,输出 -1

     

    数据规模:1 ≤ k <  n ≤ 105,0 ≤ d[i] < n

    做法分析

    第一眼做法:SPFA 或者 BFS,想了想,还是乱搞

    根据 d 数组直接构造这个图,因为最短路具有最优子结构,所以,d[i] 为 0 的点只有一个,从 0 到 maxLen 的所有距离,都一定在 d 数组中出现过,然后就考虑度数限制。

    显然,距离为 len + 1 的点是由距离为 len 的点到达的,于是,将所有的点按照距离分类。要尽量满足度数限制,每个点的度数就要尽量少,所以,距离相同的点之间不能有边。于是,构造出来的解中,所有的边 (u, v) 一定满足这样的性质:d[u] == d[v] + 1(假设 d[u] > d[v]),这让我想起了 ISAP 求最大流的 gap 优化

    然后,怎么保证每个点都尽量满足度数限制呢?平均分配

    将距离为 len + 1 的点平均分配到距离为 len 的点里面去,这样一定是最优的,如果这样都不满足度数限制,肯定无解了

    参考代码

     1 #include <iostream>
     2 #include <vector>
     3 #include <cstring>
     4 #include <cstdio>
     5 #include <algorithm>
     6 
     7 using namespace std;
     8 
     9 const int N = 100005;
    10 
    11 int k, n, d[N];
    12 vector <int> len[N];
    13 vector < pair <int, int> > edge;
    14 
    15 int main() {
    16     scanf("%d%d", &n, &k);
    17     for (int i = 0; i <= n; i ++) len[i].clear();
    18     for (int i = 1; i <= n; i ++) {
    19         scanf("%d", &d[i]);
    20         len[d[i]].push_back(i);
    21     }
    22     if (len[0].size() != 1) {
    23         printf("-1
    ");
    24         return 0;
    25     }
    26     int maxLen = n;
    27     for (; len[maxLen].size() == 0; maxLen --);
    28     for (int i = 0; i <= maxLen; i ++) {
    29         if (len[i].size() == 0) {
    30             printf("-1
    ");
    31             return 0;
    32         }
    33     }
    34     edge.clear();
    35     for (int i = 1; i <= maxLen; i ++) {
    36         int cnt1 = (int)len[i - 1].size();
    37         int cnt2 = (int)len[i].size();
    38         int cnt = cnt2 / cnt1 + (cnt2 % cnt1 != 0);
    39         if (cnt + (i - 1 != 0) > k) {
    40             printf("-1
    ");
    41             return 0;
    42         }
    43         for (int id1 = 0, id2 = 0; id1 < cnt1 && id2 < cnt2; id1 ++) {
    44             for (; id2 < (id1 + 1) * cnt && id2 < cnt2; id2 ++) {
    45                 edge.push_back(make_pair(len[i - 1][id1], len[i][id2]));
    46             }
    47         }
    48     }
    49     int cnt = (int)edge.size();
    50     printf("%d
    ", cnt);
    51     for (int i = 0; i < cnt; i ++) {
    52         printf("%d %d
    ", edge[i].first, edge[i].second);
    53     }
    54     return 0;
    55 }
    C. Restore Graph

    题目链接

    C. Restore Graph

  • 相关阅读:
    逻辑运算符&逻辑短路
    python运算符&优先性
    python类型强转&二级容器
    python中转义符&str格式化
    python中变量的缓存机制
    底层二进制的计算
    python容器数据类型的特色
    进制的转化
    shell脚本学习(1)-菜鸟教程
    python中yield的用法-简单明了!
  • 原文地址:https://www.cnblogs.com/zhj5chengfeng/p/3614563.html
Copyright © 2011-2022 走看看