题意:从某个点出发,所有点都走过且最多走两次,问最小花费
分析:数据量这么小应该是状压题,旅行商TSP的变形。dp[st][i]表示状态st,在i点时的最小花费,用三进制状压。以后任意进制状压都会了。
#include <bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; const int N = 11; int dp[60000][10]; int bit[N]; int d[N][N]; int p[N]; int n, m; void init(void) { //三进制0 1 2 bit[0] = 1; for (int i=1; i<N; ++i) { bit[i] = bit[i-1] * 3; //bit[i] 相当于在二进制下的 1 << i } } void get_status(int st) { int i = 0; memset (p, 0, sizeof (p)); while (st) { p[i++] = st % 3; st /= 3; } } int sum(void) { int ret = 0; for (int i=0; i<n; ++i) { ret += p[i] * bit[i]; } return ret; } int main(void) { init (); while (scanf ("%d%d", &n, &m) == 2) { memset (d, INF, sizeof (d)); for (int u, v, w, i=0; i<m; ++i) { scanf ("%d%d%d", &u, &v, &w); u--; v--; d[u][v] = d[v][u] = min (d[v][u], w); } int ans = INF; memset (dp, INF, sizeof (dp)); for (int i=0; i<n; ++i) { //初始化,三进制下10000的状态,现在在第i个点时花费0 dp[bit[i]][i] = 0; } for (int i=0; i<bit[n]; ++i) { bool flag = true; get_status (i); for (int j=0; j<n; ++j) { if (p[j] == 0) flag = false; if (dp[i][j] == INF) continue; for (int k=0; k<n; ++k) { if (p[k] == 2 || d[j][k] == INF || k == j) continue; p[k]++; int v = sum (); dp[v][k] = min (dp[v][k], dp[i][j] + d[j][k]); p[k]--; } } if (flag) { //每个点至少都走过一次的状态 for (int j=0; j<n; ++j) { ans = min (ans, dp[i][j]); } } } if (ans == INF) ans = -1; printf ("%d\n", ans); } return 0; }