【题目链接】
【思路要点】
- 可以直接用基于连通性的的动态规划求解,或者可以用斯坦纳树DP+SPFA求解。
- 时间复杂度\(O(N*M*3^K)\)。
【代码】
#include<bits/stdc++.h> using namespace std; #define MAXN 15 #define MAXQ 2000005 #define CURR 1024 #define INF 1e9 struct pos {int x, y, curr; }; int ans[MAXN][MAXN][CURR]; pos path[MAXN][MAXN][CURR]; int n, m, k, value[MAXN][MAXN], num[MAXN][MAXN]; bool inq[MAXN][MAXN][CURR], mark[MAXN][MAXN]; void work(pos home) { mark[home.x][home.y] = true; if (path[home.x][home.y][home.curr].curr == 0) return; pos tmp = path[home.x][home.y][home.curr]; if (home.curr == tmp.curr) work(tmp); else work(tmp), work((pos) {tmp.x, tmp.y, home.curr ^ tmp.curr}); } void update(int pi, int pj, int pc, int ti, int tj, int tc, int delta) { int tmp = ans[ti][tj][tc] + delta; if (tmp < ans[pi][pj][pc]) { ans[pi][pj][pc] = tmp; path[pi][pj][pc] = (pos) {ti, tj, tc}; } } void push(pos a) { inq[a.x][a.y][a.curr] = true; } void pop(pos a) { inq[a.x][a.y][a.curr] = false; } bool query(pos a) { return inq[a.x][a.y][a.curr]; } int main() { cin >> n >> m; k = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { cin >> value[i][j]; if (value[i][j] == 0) num[i][j] = k++; } for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) for (int curr = 1; curr < 1 << k; curr++) if (value[i][j] == 0 && curr == 1 << num[i][j]) ans[i][j][curr] = 0; else ans[i][j][curr] = INF; for (int curr = 1; curr < 1 << k; curr++) { static pos q[MAXQ]; int l = 0, r = -1; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { for (int l = (curr - 1) & curr; l; l = (l - 1) & curr) update(i, j, curr, i, j, l, ans[i][j][curr ^ l] - value[i][j]); if (ans[i][j][curr] < INF) { q[++r] = (pos) {i, j, curr}; push(q[r]); } } while (l <= r) { pos tmp = q[l++]; pop(tmp); if (ans[tmp.x][tmp.y][tmp.curr] + value[tmp.x][tmp.y + 1] < ans[tmp.x][tmp.y + 1][tmp.curr]) { ans[tmp.x][tmp.y + 1][tmp.curr] = ans[tmp.x][tmp.y][tmp.curr] + value[tmp.x][tmp.y + 1]; path[tmp.x][tmp.y + 1][tmp.curr] = tmp; if (!query((pos) {tmp.x, tmp.y + 1, tmp.curr})) { q[++r] = (pos) {tmp.x, tmp.y + 1, tmp.curr}; push(q[r]); } } if (ans[tmp.x][tmp.y][tmp.curr] + value[tmp.x][tmp.y - 1] < ans[tmp.x][tmp.y - 1][tmp.curr]) { ans[tmp.x][tmp.y - 1][tmp.curr] = ans[tmp.x][tmp.y][tmp.curr] + value[tmp.x][tmp.y - 1]; path[tmp.x][tmp.y - 1][tmp.curr] = tmp; if (!query((pos) {tmp.x, tmp.y - 1, tmp.curr})) { q[++r] = (pos) {tmp.x, tmp.y - 1, tmp.curr}; push(q[r]); } } if (ans[tmp.x][tmp.y][tmp.curr] + value[tmp.x + 1][tmp.y] < ans[tmp.x + 1][tmp.y][tmp.curr]) { ans[tmp.x + 1][tmp.y][tmp.curr] = ans[tmp.x][tmp.y][tmp.curr] + value[tmp.x + 1][tmp.y]; path[tmp.x + 1][tmp.y][tmp.curr] = tmp; if (!query((pos) {tmp.x + 1, tmp.y, tmp.curr})) { q[++r] = (pos) {tmp.x + 1, tmp.y, tmp.curr}; push(q[r]); } } if (ans[tmp.x][tmp.y][tmp.curr] + value[tmp.x - 1][tmp.y] < ans[tmp.x - 1][tmp.y][tmp.curr]) { ans[tmp.x - 1][tmp.y][tmp.curr] = ans[tmp.x][tmp.y][tmp.curr] + value[tmp.x - 1][tmp.y]; path[tmp.x - 1][tmp.y][tmp.curr] = tmp; if (!query((pos) {tmp.x - 1, tmp.y, tmp.curr})) { q[++r] = (pos) {tmp.x - 1, tmp.y, tmp.curr}; push(q[r]); } } } } int finalans = INF, goal = (1 << k) - 1; pos home; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) if (ans[i][j][goal] < finalans) { finalans = ans[i][j][goal]; home = (pos) {i, j, goal}; } cout << finalans << endl; work(home); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) if (mark[i][j]) { if (value[i][j]) cout << 'o'; else cout << 'x'; } else cout << '_'; cout << endl; } return 0; }