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\n");
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\n");
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\n");
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\n", cnt);
51     for (int i = 0; i < cnt; i ++) {
52         printf("%d %d\n", edge[i].first, edge[i].second);
53     }
54     return 0;
55 }
C. Restore Graph

 

题目链接

 

C. Restore Graph

 

 

 

posted @ 2014-03-20 20:34  jianzhang.zj  阅读(457)  评论(0编辑  收藏  举报