您的位置:首页 > 其它

BZOJ 2595: [Wc2008]游览计划 斯坦纳树

2016-09-02 10:33 295 查看
题意:连通n个景点的最小生成树(斯坦纳树)

用spfa转移dp方程,具体转移方式见hdu4085博文

此题还需要输出哪些边被用到了。这里记录一下每次转移的前继,最后从最优解开始,沿着前继边dfs,记录一下被访问到的边,最后按顺序输出被标记的边即可。

注:可以用三个数组记录前继,写起来更方便

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<map>
#define PIII pair< pair<int,int>, int>
#define X first
#define Y second
#define MP make_pair
#define ll long long
#define mem(a, b) memset(a,b,sizeof(a))
using namespace std;

const int maxn = 15;
const int maxm = 1200;
const int INF = 0x3f3f3f3f;
const int maxq = maxn*maxn;
int n, m, cnt, ma[maxn][maxn], dp[maxn][maxn][maxm], hd, tail;
int q[maxq], vis[maxq];
int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
PIII pre[maxn][maxn][maxm];

void spfa(int s){
while(tail != hd){
int u = q[hd++], x = u/m+1, y = u%m+1; hd %= maxq, vis[u] = 0;
for(int k = 0; k < 4; k ++){
int nx = x + dir[k][0], ny = y + dir[k][1], v = (nx-1)*m+ny-1;
if(nx <= 0 || nx > n || ny <= 0 || ny > m) continue;
if(dp[nx][ny][s] > dp[x][y][s] + ma[nx][ny]){
dp[nx][ny][s] = dp[x][y][s] + ma[nx][ny];
pre[nx][ny][s] = MP(MP(x, y), s);
if(!vis[v]) q[tail++] = v, tail %= maxq, vis[v] = 1;
}
}
}
}

void dfs(int i, int j, int k){
vis[(i-1)*m+j-1] = 1;
if(pre[i][j][k].X.X == -1) return;
dfs(pre[i][j][k].X.X,pre[i][j][k].X.Y,pre[i][j][k].Y);
if(pre[i][j][k].X.X == i && pre[i][j][k].X.Y == j) dfs(pre[i][j][k].X.X,pre[i][j][k].X.Y, k ^ pre[i][j][k].Y);
}

int main(){
//freopen("input.txt", "r", stdin);
scanf("%d%d", &n, &m);
mem(dp, INF);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++){
scanf("%d", &ma[i][j]);
if(!ma[i][j]) dp[i][j][1<<cnt] = 0, cnt++;
}
for(int k = 1; k < (1<<cnt); k ++){
hd = tail = 0;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++){
pre[i][j][k] = MP(MP(-1, -1), -1);
for(int s = k; s; s = (s-1)&k){
if(dp[i][j][k] > dp[i][j][s] + dp[i][j][k-s] - ma[i][j]){
dp[i][j][k] = dp[i][j][s] + dp[i][j][k-s] - ma[i][j], pre[i][j][k] = MP(MP(i, j), s);
}
}
if(dp[i][j][k] < INF) vis[(i-1)*m+j-1] = 1, q[tail++] = (i-1)*m+j-1, tail %= maxq;
}
spfa(k);
}
int ans = INF, x, y;
for(int i = 1; i <= n; i ++) for(int j = 1; j<= m; j ++)
if(dp[i][j][(1<<cnt)-1] < ans) ans = dp[i][j][(1<<cnt)-1], x = i, y = j;
printf("%d\n", ans);
mem(vis, 0);
dfs(x, y, (1<<cnt)-1);
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= m; j ++){
if(!ma[i][j]) printf("x");
else if(vis[(i-1)*m+j-1]) printf("o");
else printf("_");
}
printf("\n");
}
return 0;
}


c186
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: