牛客-郊区春游(状态压缩dp)(java)(c++)

题目链接

今天春天铁子的班上组织了一场春游,在铁子的城市里有n个郊区和m条无向道路,第i条道路连接郊区Ai和Bi,路费是Ci。经过铁子和顺溜的提议,他们决定去其中的R个郊区玩耍(不考虑玩耍的顺序),但是由于他们的班费紧张,所以需要找到一条旅游路线使得他们的花费最少,假设他们制定的旅游路线为V1, V2 ,V3 … VR,那么他们的总花费为从V1到V2的花费加上V2到V3的花费依次类推,注意从铁子班上到V1的花费和从VR到铁子班上的花费是不需要考虑的,因为这两段花费由学校报销而且我们也不打算告诉你铁子学校的位置。
输入描述:
第一行三个整数n, m, R(2 ≤ n ≤ 200, 1 ≤ m ≤ 5000, 2 ≤ R ≤ min(n, 15))。
第二行R个整数表示需要去玩耍的郊区编号。
以下m行每行Ai, Bi, Ci(1 ≤ Ai, Bi ≤ n, Ai ≠ Bi, Ci ≤ 10000)
保证不存在重边。
输出描述:
输出一行表示最小的花费

java代码

import java.util.*;

 
public class Main {
    
    
 
    public static void main(String[] args) {
    
    
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int R = sc.nextInt();
        int[][] dis = new int[n + 1][n + 1];
        for(int i = 0; i <= n; i++) {
    
    
            Arrays.fill(dis[i], Integer.MAX_VALUE);
            dis[i][i] = 0;
        }
 
        int[] tar = new int[R + 1];
        for(int i = 1; i <= R; i++) {
    
    
            tar[i] = sc.nextInt();
        }
        for(int i = 0; i < m; i++) {
    
    
            int x = sc.nextInt();
            int y = sc.nextInt();
            int c = sc.nextInt();
            dis[x][y] = c;
            dis[y][x] = c;
        }
        //floyd
        for(int k = 1; k <= n; k++) {
    
    
            for(int i = 1; i <= n; i++) {
    
    
                for(int j = i + 1; j <= n; j++) {
    
    
                    if(dis[i][k] != Integer.MAX_VALUE && dis[k][j] != Integer.MAX_VALUE) {
    
    
                        dis[i][j] = Math.min(dis[i][j], dis[i][k] + dis[k][j]);
                        dis[j][i] = dis[i][j];
                    }
                }
            }
        }
        dis[0][0] = 0;
        int s = 1 << R;
        int[][] dp = new int[s + 1][R + 1];
        for(int i = 0; i <= s; i++) {
    
    
            Arrays.fill(dp[i], Integer.MAX_VALUE);
        }
//        dp[0][0] = 0;
        //traverse all state
        for(int i = 1; i <= s; i++) {
    
    
 
            //choose the last arrived point
            for(int j = 1; j <= R; j++) {
    
    
                if(((i >> j - 1) & 1) > 0) {
    
    
                    //if the last arrived point is the only one
 
                    if(i == (1 << j - 1)) {
    
    
                        dp[i][j] = 0;
                    } else {
    
    
 
                        //traverse all point in this state
                        for(int k = 1; k <= R; k++) {
    
    
                            if(((i >> k - 1) & 1) > 0 && k != j) {
    
    
//                                dp[i][j] = Math.min(dp[i ^ k ^ j][k] + dis[tar[k]][tar[j]], dp[i][j]);
                                dp[i][j] = Math.min(dp[i ^ (1 << j - 1)][k] + dis[tar[k]][tar[j]], dp[i][j]);
 
                            }
                        }
                    }
                }
            }
        }
 
        int ans = Integer.MAX_VALUE;
        for(int i = 1; i <= R; i++) {
    
    
            ans = Math.min(ans, dp[(1 << R)- 1][i]);
        }
        System.out.println(ans);
    }
}

c++代码

#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++) {
    
    
        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/jahup/article/details/105812587