Codeforces 1026D - Shortest Cycle

题目链接:Codeforces 1026D

根据鸽巢原理,当抽屉数量为 \(64\) 的时候,如果大于 \(64 \times 2 + 1 = 129\) 个物品,可以保证有一个抽屉中出现三个物品。也就是说,在这一题中,我们只需要去掉所有为零的元素,在剩下的 \(r\) 个元素中随意取 \(\min \{ r, 129  \}\) 个出来寻找最小环即可。

这里可以使用 Floyd 算法求最小环,时间复杂度 \(O(129 ^ 3)\)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <cstdio>
#include <algorithm>
#include <climits>
using namespace std;
typedef long long LL;
const int MAX_N = 100000 + 5;
const int MAX_V = 129 + 5;
const LL INF = LL(1E15);
int n, tot, up;
LL a[MAX_N], b[MAX_N];
LL v[MAX_V][MAX_V], d[MAX_V][MAX_V];
LL minCir = INF;
void floyd() {
for (int i = 1; i <= up; ++i) {
for (int j = 1; j <= up; ++j) {
d[i][j] = v[i][j];
}
}
for (int k = 1; k <= up; ++k) {
for (int i = 1; i < k; ++i) {
for (int j = 1; j < i; ++j) {
minCir = min(minCir, d[i][j] + v[i][k] + v[k][j]);
}
}
for (int i = 1; i <= up; ++i) {
for (int j = 1; j <= up; ++j) {
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
}
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%lld", a + i);
for (int i = 1; i <= n; ++i) if (a[i]) b[++tot] = a[i];
up = min(tot, 129);
for (int i = 1; i <= up; ++i) {
for (int j = i + 1; j <= up; ++j) {
if (b[i] & b[j]) {
v[i][j] = v[j][i] = 1;
} else {
v[i][j] = v[j][i] = INF;
}
}
}
floyd();
if (minCir == INF) puts("-1");
else printf("%lld\n", minCir);
return 0;
}