传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2595
【题解】
斯坦纳树模板题。学了一发斯坦纳树。
对于一般的斯坦纳树,是 给出一些点和一些关键点和边,要求选择权值和最小的连通块使得关键点连通。
那么一般我们用f(x,status)表示在x,状态为status的最小权值和。
本题我们采用f(i,j,status)表示在(i,j),状态为status的最小权值和。
一开始权值就是题目给的,如果是景点那么在对应的标号的status赋值即可。
首先可以分成两个部分来转移:f(i,j,status) = f(i, j, subset) + f(i, j, status - subset) - mp[i][j]
(也就是枚举子集,因为(i,j)被多算了一次,所以要减掉)
另外一面,f(i, j, status) = min(f(i‘, j‘, s‘) + mp[i][j])
(从周围四个格子转移过来,增加一个格子,如果是景点需要特别处理下s‘)
这个式子长得非常像最短路,所以我们可以用spfa来解决。
然后就处理完了。接着说输出答案。
我们记录从哪里转移得到即可。递归下去处理答案并输出。
好麻烦啊qwq第一次题解写这么长呀。
不过斯坦纳树应用好像不大多,了解就行。
# include <queue> # include <stdio.h> # include <string.h> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 10 + 10, STATUS = 1027, N = 500010; const int mod = 1e9+7; # define RG register # define ST static int n, m, k = 0; int mp[M][M], st[M][M]; int f[M][M][STATUS]; const int dx[] = {1, -1, 0, 0}, dy[] = {0, 0, 1, -1}; struct pa { int i, j, s; pa() {} pa(int i, int j, int s) : i(i), j(j), s(s) {} inline int set() { return i+11*j+11*11*s; } friend bool operator == (pa a, pa b) { return a.i == b.i && a.j == b.j && a.s == b.s; } }; pa from[M][M][STATUS]; queue<pa> q; bool vis[N]; bool ans[M][M]; inline void getans(int x, int y, int s) { ans[x][y] = 1; pa t = from[x][y][s]; if(t == pa(-1, -1, -1)) return ; getans(t.i, t.j, t.s); if(t.i==x && t.j==y) getans(t.i, t.j, s-t.s); } int main() { for (int i=1; i<=10; ++i) for (int j=1; j<=10; ++j) for (int k=0; k<=1025; ++k) f[i][j][k] = 1e9, from[i][j][k] = pa(-1, -1, -1); scanf("%d%d", &n, &m); for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) { f[i][j][0] = mp[i][j]; scanf("%d", &mp[i][j]); if(mp[i][j] == 0) f[i][j][1<<k] = 0, st[i][j] = (1<<k), ++k; } int status_size = (1<<k)-1; for (int status=1; status<=status_size; ++status) { for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) { for (int ss = status-1&status; ss; ss=ss-1&status) { if(f[i][j][status] > f[i][j][ss] + f[i][j][status^ss] - mp[i][j]) { f[i][j][status] = f[i][j][ss] + f[i][j][status^ss] - mp[i][j]; from[i][j][status] = pa(i, j, ss); } } if(f[i][j][status] != 1e9) { pa t = pa(i, j, status); q.push(t); vis[t.set()] = 1; } } while(!q.empty()) { pa top = q.front(); q.pop(); vis[top.set()] = 0; for (int i=0; i<4; ++i) { int xx = top.i+dx[i], yy = top.j+dy[i]; if(xx<1 || yy<1 || xx>n || yy>m) continue; int ss = (top.s | st[xx][yy]); if(f[xx][yy][ss] > f[top.i][top.j][top.s] + mp[xx][yy]) { f[xx][yy][ss] = f[top.i][top.j][top.s] + mp[xx][yy]; from[xx][yy][ss] = top; pa ns = pa(xx, yy, ss); if(!vis[ns.set()]) { vis[ns.set()] = 1; q.push(ns); } } } } } for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) { if(!mp[i][j]) { printf("%d\n", f[i][j][status_size]); getans(i, j, status_size); for (int x=1; x<=n; ++x, puts("")) for (int y=1; y<=m; ++y) if(ans[x][y]) { if(mp[x][y]) printf("o"); else printf("x"); } else printf("_"); i = n+1, j = m+1; } } return 0; }
时间: 2024-12-21 23:32:12