Shortest Good Path(分层图BFS)
题意
给定一个\(N\)个点\(M\)条边的简单连通无向图。
令\(S = s_1s_2\dots s_N\)是一个长度为\(N\)的\(01\)串。一个路径\(A\)为关于\(S\)的一个好路径,需要满足如下条件:
- 对于所有的\(i = 1, 2, \dots, N\),如果\(s_i = 0\),则\(A\)经过\(i\)偶数次;如果\(s_i = 1\),则\(A\)经过\(i\)奇数次。
总共有\(2^N\)个\(S\),求每个\(S\)的最短好路径长度之和。
数据范围
\(2 \leq N \leq 17\)
思路
将不同的\(S\)看作分层图的层,\(d(i, j)\)表示到\(i\)点,且\(S\)为\(j\)时的最短路径长度。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int N = 20, M = 1 << N;
int n, m;
int h[N], e[N * N], ne[N * N], idx;
int d[N][M];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
int main()
{
memset(h, -1, sizeof h);
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i ++) {
int a, b;
scanf("%d%d", &a, &b);
a --, b --;
add(a, b), add(b, a);
}
memset(d, 0x3f, sizeof d);
queue<pii> que;
for(int i = 0; i < n; i ++) {
d[i][1 << i] = 1;
que.push({i, 1 << i});
}
while(que.size()) {
auto t = que.front();
que.pop();
int ts = t.second, tv = t.first;
for(int i = h[tv]; ~i; i = ne[i]) {
int j = e[i];
int u = ts ^ (1 << j);
if(d[j][u] > d[tv][ts] + 1) {
d[j][u] = d[tv][ts] + 1;
que.push({j, u});
}
}
}
ll ans = 0;
for(int i = 1; i < 1 << n; i ++) {
int t = 0x3f3f3f3f;
for(int k = 0; k < n; k ++) {
t = min(d[k][i], t);
}
ans += t;
}
printf("%lld\n", ans);
return 0;
}