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