题目
题解思路
将每个点跳或者不跳转化成二进制来表示状态。
dp[ i ] [ j ] [ k ]
集合 表示 当前状态为i,且在站在j上,使用两次加速的情况为 k 的 所有合法方案的代价 。
属性 代价的min
转移方程其实挺好推的,因为是很明确的哪个点到哪个点。(就是不要漏了情况)
参考题解
AC代码
#include <bits/stdc++.h>
//#include <unordered_map>
//priority_queue
#define PII pair<int,int>
#define ll long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 200100 , M = 1 << 17 ;
long long a[50][50] ;
long long dp[M][20][5] ;
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int n ;
cin >> n ;
for (int i = 0 ; i < n ; i++ )
for (int j = 0 ; j < n ; j++ )
cin >> a[i][j] ;
memset( dp , 0x3f , sizeof(dp) ) ;
for (int i = 0 ; i < n ; i++ )
{
dp[1<<i][i][0] = 0 ;
}
for (int i = 0 ; i < 1 << n ; i++ )
{
for (int j = 0 ; j < n ;j++ )
{
if ( (i >> j & 1 ))
{
for (int t = 0 ; t < n ; t++ )
{
int st = i | ( 1 << t) ;
if ( !(i >> t & 1) )
{
dp[st][t][0] = min(dp[st][t][0] , dp[i][j][0] + a[j][t] ) ;
dp[st][t][1] = min(dp[st][t][1] , dp[i][j][0] + 2*a[j][t]) ;
dp[st][t][1] = min(dp[st][t][1] , dp[i][j][1] + a[j][t] ) ;
dp[st][t][2] = min(dp[st][t][2] , dp[i][j][0] ) ;
dp[st][t][2] = min(dp[st][t][2] , dp[i][j][2] + a[j][t] ) ;
dp[st][t][3] = min(dp[st][t][3] , min(dp[i][j][1] , dp[i][j][2] + 2*a[j][t])) ;
dp[st][t][3] = min(dp[st][t][3] , dp[i][j][3] + a[j][t] ) ;
}
}
}
}
}
long long res = INF ;
for (int i = 0 ; i < n ; i++ )
{
res = min(res,dp[(1<<n)-1][i][3]) ;
}
cout << res << "\n" ;
return 0 ;
}