【LG4294】[WC2008]游览计划
【LG4294】[WC2008]游览计划
题面
题解
斯坦纳树板子题。
斯坦纳树的总结先留个坑。
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
inline int gi() {
register int data = 0, w = 1;
register char ch = 0;
while (!isdigit(ch) && ch != '-') ch = getchar();
if (ch == '-') w = -1, ch = getchar();
while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
return w * data;
}
typedef pair<int, int> P;
typedef pair<P, int> Pi;
#define fi first
#define se second
const int INF = 0x3f3f3f3f;
int N, M, K, rt, f[105][1111], a[105], ans[15][15];
bool inq[105];
Pi pre[105][1111];
const int dx[] = {0, 0, -1, 1} ;
const int dy[] = {1, -1, 0, 0} ;
queue<P> que;
bool check(P x) { return x.fi >= 0 && x.se >= 0 && x.fi < N && x.se < M; }
#define num(u) (u.fi * M + u.se)
void spfa(int o) {
while (!que.empty()) {
P x = que.front(); que.pop(); inq[num(x)] = 0;
for (int i = 0; i < 4; i++) {
P v = make_pair(x.fi + dx[i], x.se + dy[i]);
int nx = num(x), nv = num(v);
if (check(v) && f[nv][o] > f[nx][o] + a[nv]) {
f[nv][o] = f[nx][o] + a[nv];
if (!inq[nv]) inq[nv] = 1, que.push(v);
pre[nv][o] = make_pair(x, o);
}
}
}
}
void dfs(P x, int o) {
if (!pre[num(x)][o].se) return ;
ans[x.fi][x.se] = 1;
int nx = num(x);
if (pre[nx][o].fi == x) dfs(x, o ^ pre[nx][o].se);
dfs(pre[nx][o].fi, pre[nx][o].se);
}
int main () {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
#endif
cin >> N >> M;
memset(f, 0x3f, sizeof(f));
for (int i = 0, tot = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
cin >> a[tot];
if (!a[tot]) f[tot][1 << (K++)] = 0, rt = tot;
++tot;
}
}
for (int o = 1; o < (1 << K); o++) {
for (int i = 0; i < N * M; i++) {
for (int s = o & (o - 1); s; s = o & (s - 1))
if (f[i][o] > f[i][s] + f[i][o ^ s] - a[i]) {
f[i][o] = f[i][s] + f[i][o ^ s] - a[i];
pre[i][o] = make_pair(make_pair(i / M, i % M), s);
}
if (f[i][o] < INF) que.push(make_pair(i / M, i % M)), inq[i] = 1;
}
spfa(o);
}
cout << f[rt][(1 << K) - 1] << endl;
dfs(make_pair(rt / M, rt % M), (1 << K) - 1);
for (int i = 0, tot = 0; i < N; i++){
for (int j = 0; j < M; j++)
if (!a[tot++]) putchar('x');
else putchar(ans[i][j] ? 'o' : '_');
printf("\n");
}
return 0;
}