$dp[i][state]$ 表示以$i$为根,指定集合中的点的连通状态为state的生成树的最小总权值
有两种转移方向:
1、先通过连通状态的子集进行转移。
2、在当前枚举的连通状态下,对该连通状态进行松弛操作。
P4294 [WC2008]游览计划
注意景点的个数不超过10个。
$dp[i][j][state]$ 表示在$[i, j]$这个点与state中对应点连通的最小代价。
那么就可以用状压DP + spfa求解。
由于要输出方案,可以记录每个状态的前一个状态,最后dfs跑一遍就行了。
// #pragma GCC optimize(2) // #pragma GCC optimize(3) // #pragma GCC optimize(4) #include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include <bitset> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <stack> #include <cmath> #include <queue> #include <list> #include <map> #include <set> #include <cassert> #include <unordered_set> #include <unordered_map> // #include<bits/extc++.h> // using namespace __gnu_pbds; using namespace std; #define pb push_back #define fi first #define se second #define debug(x) cerr<<#x << " := " << x << endl; #define bug cerr<<"-----------------------"<<endl; #define FOR(a, b, c) for(int a = b; a <= c; ++ a) typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; const int inf = 0x3f3f3f3f; const ll inff = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9+7; template<typename T> inline T read(T&x){ x=0;int f=0;char ch=getchar(); while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x=f?-x:x; } /**********showtime************/ const int maxn = 12; int a[maxn][maxn]; int dp[maxn][maxn][1055]; struct node{ int x, y, state; } pre[maxn][maxn][1055]; queue<pii>que; int nx[4][2] = { {0, 1}, {1, 0},{-1,0},{0,-1} }; int n,m; int vis[maxn][maxn]; void spfa(int now) { while(!que.empty()) { pii tmp = que.front(); que.pop(); for(int i=0; i<4; i++) { int x = tmp.fi + nx[i][0]; int y = tmp.se + nx[i][1]; if(x < 1 || x > n || y < 1 || y > m) continue; if(dp[x][y][now] > dp[tmp.fi][tmp.se][now] + a[x][y]) { dp[x][y][now] = dp[tmp.fi][tmp.se][now] + a[x][y]; pre[x][y][now] = node{tmp.fi, tmp.se, now}; if(!vis[x][y]) { que.push(pii(x, y)); vis[x][y] = 1; } } } vis[tmp.fi][tmp.se] = 0; } } void dfs(int x, int y, int now) { if(x == 0 || y == 0) return; vis[x][y] = 1; node tmp = pre[x][y][now]; dfs(tmp.x, tmp.y, tmp.state); if(tmp.x == x && tmp.y == y) dfs(tmp.x, tmp.y, now - tmp.state); } int main(){ scanf("%d%d", &n, &m); memset(dp, inf, sizeof(dp)); int num = 0; for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { scanf("%d", &a[i][j]); if(a[i][j] == 0) { dp[i][j][(1<<num)] = 0; num++; } } } int all = (1<<num) - 1; for(int state = 0; state <= all; state ++) { for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { for(int s0 = (s0-1) & state; s0; s0 = (s0-1) & state) { if(dp[i][j][state] > dp[i][j][s0] + dp[i][j][state - s0] - a[i][j]) { dp[i][j][state] = dp[i][j][s0] + dp[i][j][state - s0] - a[i][j]; pre[i][j][state] = node{i, j, s0}; } } if(dp[i][j][state] < inf) que.push(pii(i, j)), vis[i][j] = 1; } } spfa(state); } int ax, ay, mn = inf; for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { if(dp[i][j][all] < mn) { mn = dp[i][j][all]; ax = i; ay = j; } } } printf("%d\n", mn); memset(vis, 0, sizeof(vis)); dfs(ax, ay, all); for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { if(a[i][j] == 0) printf("x"); else if(vis[i][j]) printf("o"); else printf("_"); } puts(""); } return 0; }