标签:http cstring hid first 裸题 网格 struct org scan
题意
给定一个 $N \times M$ 的网格图,每个格子与四个方向上相邻的格子联通,其中有 $K$ 个点是景点。非景点格子有正点权 $A_{i,j}$,你需要选择一些格子使得所有景点联通,求最小点权和并输出选点方案。
数据范围
$N,M,K \leq 10$
分析
我怀疑我在水博客,但是我没有证据
这很显然是个最小斯坦纳树,经典例题裸题
设 $f[i][j][s]$ 表示以点 $(i,j)$ 为根,点集 $s$ 都在树上的生成树最小点权
于是有两个状态转移方程 $$f[i][j][s]=min_{k \subsetneq s}\{f[i][j][k]+f[i][j][s-k]-a[i][j]\}$$ $$f[i][j][k]=min_{\vert i‘-i \vert + \vert j‘-j \vert =1}\{f[i‘][j‘][s]+a[i][j]\}$$
但由于题目要求输出选点方案,所以我们要记录每个状态最后被更新时的前继状态,以便最后返回遍历所有用过的点
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <queue> #include <set> using namespace std; #define ll long long #define inf 0x3f3f3f3f #define N 11 int n, m, p, ok, x0, y0; int g[N][N], f[N][N][1 << N], vis[N][N]; int d[4][2] = {0, 1, 1, 0, 0, -1, -1, 0}; queue<pair<int, int> > q; struct Point { int x, y, s; } pre[N][N][1 << N], tmp; void spfa(int s) { while (!q.empty()) { int x = q.front().first, y = q.front().second; q.pop(); vis[x][y] = 0; for (int i = 0; i < 4; i++) { int dx = x + d[i][0], dy = y + d[i][1]; if (dx < 1 || dx > n || dy < 1 || dy > m) continue; if (f[dx][dy][s] > f[x][y][s] + g[dx][dy]) { f[dx][dy][s] = f[x][y][s] + g[dx][dy]; tmp.x = x; tmp.y = y; tmp.s = s; pre[dx][dy][s] = tmp; if (!vis[dx][dy]) vis[dx][dy] = 1, q.push(make_pair(dx, dy)); } } } } void dfs(int x, int y, int s) { vis[x][y] = 1; tmp = pre[x][y][s]; if (!tmp.s) return; dfs(tmp.x, tmp.y, tmp.s); tmp = pre[x][y][s]; if (tmp.x == x && tmp.y == y) dfs(x, y, s ^ tmp.s); } int main() { scanf("%d%d", &n, &m); memset(f, 0x3f, sizeof f); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { scanf("%d", &g[i][j]); if (!g[i][j]) f[i][j][1 << p] = 0, p++; } for (int s = 1; s < (1 << p); s++) { for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { for (int k = s & (s - 1); k; k = (k - 1) & s) if (f[i][j][s] > f[i][j][k] + f[i][j][s ^ k] - g[i][j]) { f[i][j][s] = f[i][j][k] + f[i][j][s ^ k] - g[i][j]; tmp.x = i; tmp.y = j; tmp.s = k; pre[i][j][s] = tmp; } if (f[i][j][s] < inf) vis[i][j] = 1, q.push(make_pair(i, j)); } spfa(s); } for (int i = 1; i <= n && !ok; i++) for (int j = 1; j <= m && !ok; j++) if (!g[i][j]) x0 = i, y0 = j, ok = 1; printf("%d\n", f[x0][y0][(1 << p) - 1]); dfs(x0, y0, (1 << p) - 1); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (!g[i][j]) printf("x"); else if (vis[i][j]) printf("o"); else printf("_"); } printf("\n"); } return 0; }
标签:http cstring hid first 裸题 网格 struct org scan
原文地址:https://www.cnblogs.com/Pedesis/p/11378857.html