CF1310D - Tourism
题意
N
N
N个点的图,给你图的邻接矩阵
g
g
g,求从点
1
1
1出发经过
K
K
K条边途径偶数个城市回到点
1
1
1的最短距离
2
≤
N
≤
80
,
2
≤
K
≤
10
2\leq N \leq 80, 2\leq K \leq 10
2≤N≤80,2≤K≤10
题解
路径是一个环,并且是一个偶数环
二分图的充要条件就是不存在奇数环
所以我们可以把图染色成一个二分图,在二分图上跑dp就行
但是枚举二分图需要
O
(
2
N
)
O(2^N)
O(2N),这里会超时
所以这里随机构建二分图
然后跑一个dp,令
f
[
k
]
[
i
]
f[k][i]
f[k][i]为经过
k
k
k条边到达点
i
i
i的最短距离
若
c
o
l
o
r
[
i
]
!
=
c
o
l
o
r
[
j
]
color[i] != color[j]
color[i]!=color[j],则有转移方程
f
[
k
]
[
j
]
=
m
i
n
(
f
[
k
]
[
j
]
,
f
[
k
−
1
]
[
i
]
+
g
[
i
]
[
j
]
)
f[k][j]=min(f[k][j],f[k-1][i]+g[i][j])
f[k][j]=min(f[k][j],f[k−1][i]+g[i][j])
代码
#include <bits/stdc++.h>
#define sz sizeof
using namespace std;
typedef long long ll;
const int MAX = 1e2 + 10;
int N, K;
int c[MAX];
ll g[MAX][MAX], f[15][MAX];
int main() {
//auto start_clock = clock();
srand(time(0));
scanf("%d%d", &N, &K);
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
scanf("%lld", &g[i][j]);
ll ans = 9e18;
int T = 3000;//我是随机3000次二分图
while (T--) {//或者运行时间小于题目时限就继续运行,即(clock() - start_clock) / CLOCKS_PER_SEC < 2.9
for (int i = 1; i <= N; i++) c[i] = rand() % 2;//二分图染色
memset(f, 0x3f, sz(f));
f[0][1] = 0;
for (int k = 1; k <= K; k++)
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
if (c[i] != c[j])
f[k][j] = min(f[k][j], f[k - 1][i] + g[i][j]);
ans = min(ans, f[K][1]);
}
printf("%lld\n", ans);
return 0;
}