CF_152E
这个题目只需要求一棵斯坦纳树,但是蛋疼的是需要打印路径,因此要多开一个数组记录路径。一种还算比较省事的记录路径的办法就是如果是spfa拓展出来的状态就用负数记录一下拓展的方向,如果是子树组合出来的状态就用正数记录一下其中一棵子树的点集状态,这样能很方便的求出另一棵子树的点集状态。
#include<stdio.h> #include<string.h> #define MAXN 110 #define ST 138 #define MAXQ 256010 #define INF 0x3f3f3f3f const int Q = 256000; int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1}; int N, M, K, a[MAXN][MAXN]; int bit[MAXN][MAXN], f[MAXN][MAXN][ST], pre[MAXN][MAXN][ST], vis[MAXN][MAXN]; struct point { int x, y, st; point(){} point(int _x, int _y, int _st) : x(_x), y(_y), st(_st){} }q[MAXQ]; int front, rear, inq[MAXN][MAXN][ST]; void init() { int i, j, n = 0, x, y; for(i = 1; i <= N; i ++) for(j = 1; j <= M; j ++) scanf("%d", &a[i][j]); for(i = 1; i <= N; i ++) for(j = 1; j <= M; j ++) bit[i][j] = 0, memset(f[i][j], 0x3f, sizeof(f[i][j])), memset(pre[i][j], 0x3f, sizeof(pre[i][j])); for(i = 0; i < K; i ++) { scanf("%d%d", &x, &y); bit[x][y] = 1 << (n ++), f[x][y][bit[x][y]] = a[x][y]; } } int can(int x, int y) { return x >= 1 && x <= N && y >= 1 && y <= M; } void spfa() { int i, x, y, st, nx, ny, nst; while(front != rear) { x = q[front].x, y = q[front].y, st = q[front].st, inq[x][y][st] = 0; ++ front > Q ? front = 0 : 0; for(i = 0; i < 4; i ++) { nx = dx[i] + x, ny = dy[i] + y, nst = st | bit[nx][ny]; if(can(nx, ny) && f[x][y][st] + a[nx][ny] < f[nx][ny][nst]) { f[nx][ny][nst] = f[x][y][st] + a[nx][ny], pre[nx][ny][nst] = -i; q[rear ++] = point(nx, ny, nst), inq[nx][ny][nst] = 1; rear > Q ? rear = 0 : 0; } } } } void dfs(int x, int y, int st) { vis[x][y] = 1; if(pre[x][y][st] == INF) return ; if(pre[x][y][st] <= 0) dfs(x - dx[-pre[x][y][st]], y - dy[-pre[x][y][st]], st - bit[x][y]); else dfs(x, y, pre[x][y][st]), dfs(x, y, st - pre[x][y][st] | bit[x][y]); } void solve() { int i, j, k, x, y, st, nn = 1 << K, ans; front = rear = 0; for(i = 1; i <= N; i ++) for(j = 1; j <= M; j ++) memset(inq[i][j], 0, sizeof(inq[i][j])), vis[i][j] = 0; for(i = 0; i < nn; i ++) { for(j = 1; j <= N; j ++) for(k = 1; k <= M; k ++) { for(st = i & i - 1; st; st = st - 1 & i) { int temp = f[j][k][st | bit[j][k]] + f[j][k][i - st | bit[j][k]] - a[j][k]; if(temp < f[j][k][i]) f[j][k][i] = temp, pre[j][k][i] = st | bit[j][k]; } if(f[j][k][i] < INF) { q[rear ++] = point(j, k, i), inq[j][k][i] = 1; rear > Q ? rear = 0 : 0; } } spfa(); } ans = INF; for(i = 1; i <= N; i ++) for(j = 1; j <= M; j ++) if(f[i][j][nn - 1] < ans) ans = f[i][j][nn - 1], x = i, y = j; dfs(x, y, nn - 1); printf("%d\n", ans); for(i = 1; i <= N; i ++) { for(j = 1; j <= M; j ++) printf("%c", vis[i][j] ? 'X' : '.'); printf("\n"); } } int main() { while(scanf("%d%d%d", &N, &M, &K) == 3) { init(); solve(); } return 0; }