牛客小白月赛4 D.郊区春游

原题地址:https://www.nowcoder.com/acm/contest/134/D
思路:一开始以为是可以暴搜的,然后发现只过了50的样例,后来才知道原来是个状压的裸题。
先用floyd预处理每个点之间的最短路,然后对于要去的地方(最多15个,所以是状态最多不到32768)进行状压。

#include  <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 205;
int e[maxn][maxn];
int n, m, r;
int reach[maxn];
int vis[maxn];
int ans = inf;
int dp[50000][20];
int main() {
    memset(e, inf, sizeof(e));
    scanf("%d%d%d", &n, &m, &r);
    for(int i = 1; i <= r; i++) {
        scanf("%d", &reach[i]);
    }
    for(int i = 1; i <= n; i++) e[i][i] = 0;
    for(int i = 1; i <= m; i++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        e[u][v] = e[v][u] = min(e[u][v], w);
    }
    for(int k = 1; k <= n; k++) {//floyd 求 最短路
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                if(e[i][j] > e[i][k] + e[k][j]) e[i][j] = e[i][k] + e[k][j];
            }
        }
    }
    memset(dp, inf, sizeof(dp));
    for(int i = 0; i < r; i++) dp[1 << i][i + 1] = 0;
    for(int s = 0; s < (1 << r); s++) {//简单的状压
        for(int i = 1; i <= r; i++) {
            if(s & 1 << (i - 1) == 0) continue;//当前所在城市已经访问。可以去掉很多不必要的状态
            for(int j = 1; j <= r; j++) {
                if(s & 1 << (j - 1))continue;//当前要去的城市还没访问
                dp[s | 1 << (j - 1)][j] = min(dp[s | 1 << (j - 1)][j], dp[s][i] + e[reach[i]][reach[j]]);
            }
        }
    }
    int MIN = inf;
    int s = (1 << r) - 1;
    for(int i = 1; i <= r; i++) MIN = min(MIN, dp[s][i]);
    printf("%d\n", MIN);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/80731455