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;
}
posted @ 2022-03-28 18:19  pbc的成长之路  阅读(79)  评论(0编辑  收藏  举报