题目来源:算法竞赛进阶指南
题目标签:状态压缩DP,二进制状态枚举
题目链接:https://www.acwing.com/problem/content/93/
思路:1. f [ state ][ j ] : 表示在state状态下,最后一个被选中的点是 j 点。
2.枚举所有可能出现的状态和最后一个点的值。
3.枚举当前点的前一个点,当前状态可以由前一个点转移过来
*tips:题目要求终点一定是n - 1, 如果没有要求需要对终点也进行枚举取最小
代码:
#include <bits/stdc++.h> using namespace std; const int N = 20, M = 1 << 20; int n; int f[M][N], weight[N][N]; int main() { cin >> n; for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) cin >> weight[i][j]; memset(f, 0x3f, sizeof f); f[1][0] = 0; for(int i = 0; i < 1 << n; i++) //枚举所有当前的状态,那些点已经被选中过 for(int j = 0; j < n; j++) //枚举当前点是那个点 if(i >> j & 1) //保证当前点是存在于状态中的 for(int k = 0; k < n; k++) //枚举当前点的前一个点 if(i - (1 << j) >> k & 1) //保证点k存在于当前状态减去当前点后的状态(保证k点已经被经过,并且和当前点不是同一个点) f[i][j] = min(f[i][j], f[i - (1 << j)][k] + weight[k][j]); //当前状态是由K转移到当前点的最小代价 cout << f[(1 << n) - 1][n - 1] << endl; //最后状态:所有点全部被选中,已经到达最后一个点 return 0; }