【无标题】

毕业旅行问题

描述

小明目前在做一份毕业旅行的规划。打算从北京出发,分别去若干个城市,然后再回到北京,每个城市之间均乘坐高铁,且每个城市只去一次。由于经费有限,希望能够通过合理的路线安排尽可能的省一些路上的花销。给定一组城市和每对城市之间的火车票的价钱,找到每个城市只访问一次并返回起点的最小车费花销。
输入描述:
城市个数n(1<n≤20,包括北京)

城市间的车票价钱 n行n列的矩阵 m[n][n]
输出描述:
最小车费花销 s
示例1
输入:
4
0 2 6 5
2 0 4 4
6 4 0 2
5 4 2 0
复制
输出:
13
复制
说明:
共 4 个城市,城市 1 和城市 1 的车费为0,城市 1 和城市 2 之间的车费为 2,城市 1 和城市 3 之间的车费为 6,城市 1 和城市 4 之间的车费为 5,依次类推。假设任意两个城市之间均有单程票可购买,且票价在1000元以内,无需考虑极端情况。

题解

dp问题,最重要的就是理解dp[i][j]的含义,i的含义表示你所经过的点,j表示的则是你最后到达的点,记住一点就是无论如何你都是从0点开始出发,所以在i中,0点是一定存在的。
状态方程式

dp[1<<k | i][k] = min(dp[1<<k | i][k],dp[i][j] + arr[j][k]);

我们从下往上去进行一个推导dp[1111][0] = dp[1111][1] + dp[1111][2] + dp[1111][3] .
dp[0111][2] = dp [0011][1] + arr[2][1] … 可以看到的这个就很清楚了,前面指的是以2为结尾经历了0,1,2的节点 意思就是从0 出发经历1,到达2,后面的式子就是经过0,到达1 然后 加上arr[1][2] …

代码

#include <climits>
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int main() {
    //dp[i][j] ,i表示经过了多少个点,比如说0111那就是经过了0,1,2三个城市,j的话表示最后到达的那个,但是记住一点就是说无论如何都是从0开始的!
    int n,maxv = 0x7fffffff;
   // cout<<maxv;
    cin>>n;
    vector<vector<int> > arr(n,vector<int>(n));
    for(int i = 0 ; i < n ; ++i) for(int j = 0 ; j<n;++j) cin>>arr[i][j];
    int max_i = 1 << n ;
    vector<vector<int> > dp(max_i,vector<int>(n,maxv));
    dp[1][0] = 0;
    for(int i = 1 ; i < max_i ; ++i){
        for(int j = 0 ; j < n ; ++j){
            if(dp[i][j] != maxv){
                for(int k = 0 ; k < n ; ++k){
                    if((1 << k & i) == 0){
                        dp[1<<k | i][k] = min(dp[1<<k | i][k],dp[i][j] + arr[j][k]);
                    }
                }
            }
        }
    }
    
    int ans = maxv ;
    for(int i =  0;i < n;++i){
        //cout<<dp[max_i - 1][i]<<endl;
        ans = min(ans,dp[max_i - 1][i] + arr[0][i]);
    }
    cout<<ans;
    return 0;
    
    
    
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值