最难想到的是状态表示…
f[i][j]
表示的是所有从0走到j,走过的所有点是i的所有路径
属性:0到终点j的最短路径
状态计算:
转移方程:
dp[i][j]=min(dp[i][j],dp[i-(1<<j)][k]+g[k][j])
初始值 dp[1][0]=0
其他赋值为INF(求的是最小值)
所求值dp[(1<<n)-1][n-1]
注意括号
遍历方向:先遍历i(所有路径状态),然后才是终点j和中间步k
而不是j->i->k
原因是如果先遍历的是j,那么用k的时候 j可能还没有遍历到。
在这题里面,终点这一维度可以变大变小,所以要后遍历。
#include<bits/stdc++.h>
using namespace std;
const int maxn=20;
const int maxm=1<<20; //多一点就超空间
const int INF=0x3F3F3F3F;
int g[maxn][maxn];
int n;
long long dp[maxm][maxn];//前一个是状态 后一个是终点
int main(){
cin>>n;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%d",&g[i][j]);
}
}
fill(dp[0],dp[0]+maxn*maxm,INF);
dp[1][0]=0;
for(int i=0;i<1<<n;i++){
for(int j=0;j<n;j++){
for(int k=0;k<n;k++){
if((i>>j)&1){
dp[i][j]=min(dp[i][j],dp[i-(1<<j)][k]+g[k][j]);
}
}
}
}
cout<<dp[(1<<n)-1][n-1]<<endl;
}