https://ac.nowcoder.com/acm/problem/16122
旅行商问题(板子题):每个城市都得经过且仅经过一次
通过数据范围和题目模型容易看出是旅行商问题,故直接状压dp(刚开始还傻不拉几的用并查集写QAQ)
思路(旅行商问题的常见状态设置):
状态表示:dp[st][i]:走过的城市的状态为st,最后一个到达得城市为第i个城市
状态转移:dp[i][j] = min(dp[k][q] + dist[j][q])(其中dist[j][q]是dist[j][q]的最短路)
该问题满足最优子结构的证明:参见Most powerful的证明,原理一样
AC代码
#include <bits/stdc++.h> using namespace std; #define IO std::ios::sync_with_stdio(false); cin.tie(0) #define ll long long #define ull unsigned long long #define SZ(x) ((int)(x).size()) #define all(x) (x).begin(), (x).end() #define rep(i, l, r) for (int i = l; i <= r; ++i) #define per(i, l, r) for (int i = l; i >= r; --i) #define mset(s, _) memset(s, _, sizeof(s)) #define mcpy(s, _) memcpy(s, _, sizeof(s)) #define pb push_back #define pii pair <int, int> #define vi vector<int> #define vpii vector<pii> #define mp(a, b) make_pair(a, b) #define pll pair <ll, ll> #define fir first #define sec second #define inf 0x3f3f3f3f inline int lowbit(int x) {return x & -x;} template< typename T > inline void get_min(T &x, T y) {if(y < x) x = y;} template< typename T > inline void get_max(T &x, T y) {if(x < y) x = y;} inline int read() { int x = 0, f = 0; char ch = getchar(); while (!isdigit(ch)) f |= ch == '-', ch = getchar(); while (isdigit(ch)) x = 10 * x + ch - '0', ch = getchar(); return f ? -x : x; } template<typename T> inline void print(T x) { if (x < 0) putchar('-'), x = -x; if (x >= 10) print(x / 10); putchar(x % 10 + '0'); } template<typename T> inline void print(T x, char let) { print(x), putchar(let); } const int N = 200 + 10, M = 5e3 + 10, mod = 100000000; int n, m, r; int dist[N][N]; vi tar; void floyd() { for(int k = 1; k <= n; k ++ ) { for(int i = 1; i <= n; i ++ ) { for(int j = 1; j <= n; j ++ ) { dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]); } } } } ll dp[1 << 15][15]; int main() { cin >> n >> m >> r; mset(dist, 0x3f); rep(i, 1, r) { int t; cin >> t; tar.pb(t - 1); } rep(i, 1, m) { int a, b, c; cin >> a >> b >> c; dist[a - 1][b - 1] = dist[b - 1][a - 1] = min(dist[a - 1][b - 1], c); } floyd(); mset(dp, 0x3f); for(int i = 0; i < (1 << r); i ++ ) { int cnt = 0, id; for(int j = 0; j < r; j ++ ) { if(i >> j & 1) { cnt ++ ; id = j; } } if(cnt == 1) dp[i][id] = 0; } for(int i = 0; i < (1 << r); i ++ ) { for(int j = 0; j < r; j ++ ) { int x = tar[j]; if(i >> j & 1) { for(int k = 0; k < r; k ++ ) { if(k != j && (i >> k) & 1) { int y = tar[k]; dp[i][j] = min(dp[i][j], dp[i - (1 << j)][k] + dist[x][y]); } } } } } ll ans = inf; for(int i = 0; i < r; i ++ ) { ans = min(ans, dp[(1 << r) - 1][i]); } cout << ans << endl; return 0; }