BZOJ2595 [Wc2008]游览计划 【状压dp + 最短路】
2018-06-17 10:36
423 查看
题目链接
题解
著名的斯坦纳树问题
设\(f[i][j][s]\)表示点\((i,j)\)与景点联通状况为\(s\)的最小志愿者数
设\(val[i][j]\)为\((i,j)\)需要的志愿者数
有两种转移
一种是自己转移
\[f[i][j][s] = min\{f[i][j][e] + f[i][j][\complement_s e] - val[i][j]\}\]
一种是由周围转移过来
\[f[i][j][s] = min\{f[i][j][s] + f[x][y][s] + dis\}\]
第一种\(O(3^{K})\)枚举子集,第二种就是最短路
纪念一下BZOJ500题,截个图,,数字挺整的
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<vector> #include<map> #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) #define REP(i,n) for (int i = 1; i <= (n); i++) #define mp(a,b) make_pair<int,int>(a,b) #define cls(s) memset(s,0,sizeof(s)) #define cp pair<int,int> #define LL long long int using namespace std; const int maxn = 11,maxm = 1 << 10,INF = 1000000000; inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();} while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();} return out * flag; } int n,m,K,maxv; int f[maxn][maxn][maxm],val[maxn][maxn],id[maxn][maxn],vis[maxn][maxn]; int head,tail,X[4] = {0,0,-1,1},Y[4] = {-1,1,0,0}; int S[maxn][maxn]; cp q[10000]; struct tri{ int x,y,s; }; vector<tri> pre[maxn][maxn][maxm]; void spfa(int s){ head = 0; tail = -1; REP(i,n) REP(j,m) q[++tail] = mp(i,j),vis[i][j] = true; cp u; int nx,ny; while (head <= tail){ u = q[head++]; vis[u.first][u.second] = false; for (int k = 0; k < 4; k++){ nx = u.first + X[k]; ny = u.second + Y[k]; if (nx < 1 || ny < 1 || nx > n || ny > m) continue; if (f[nx][ny][s] > f[u.first][u.second][s] + val[nx][ny]){ f[nx][ny][s] = f[u.first][u.second][s] + val[nx][ny]; pre[nx][ny][s].clear(); pre[nx][ny][s].push_back((tri){u.first,u.second,s}); if (!vis[nx][ny]) q[++tail] = mp(nx,ny); } } } } void dfs(int x,int y,int s){ S[x][y] = true; tri u; for (unsigned int i = 0; i < pre[x][y][s].size(); i++){ u = pre[x][y][s][i]; dfs(u.x,u.y,u.s); } } void work(){ maxv = (1 << K) - 1; memset(f,0x3f3f3f3f,sizeof(f)); REP(i,n) REP(j,m){ f[i][j][0] = 0; if (!val[i][j]) f[i][j][1 << id[i][j] - 1] = 0; } for (int s = 0; s <= maxv; s++){ REP(i,n) REP(j,m){ for (int e = s; e; e = (e - 1) & s){ if (f[i][j][s] > f[i][j][e] + f[i][j][s ^ e] - val[i][j]){ f[i][j][s] = f[i][j][e] + f[i][j][s ^ e] - val[i][j]; pre[i][j][s].clear(); pre[i][j][s].push_back((tri){i,j,e}); pre[i][j][s].push_back((tri){i,j,s ^ e}); } } } spfa(s); } int ans = INF,x,y; REP(i,n) REP(j,m) if (ans > f[i][j][maxv]) ans = f[i][j][maxv],x = i,y = j; printf("%d\n",ans); dfs(x,y,maxv); REP(i,n){ REP(j,m){ if (id[i][j]) putchar('x'); else if (S[i][j]) putchar('o'); else putchar('_'); } puts(""); } } int main(){ n = read(); m = read(); REP(i,n) REP(j,m){ val[i][j] = read(); if (!val[i][j]) id[i][j] = ++K; } work(); return 0; }
相关文章推荐
- BZOJ 2595 [Wc2008]游览计划 SPFA+斯坦纳树 or 插头DP
- bzoj 2595: [Wc2008]游览计划(斯坦纳树)
- BZOJ2595 Wc2008 游览计划
- AC日记——[Wc2008]游览计划 bzoj 2595
- BZOJ 2595: [Wc2008]游览计划 斯坦纳树
- 【BZOJ2595】 [Wc2008]游览计划
- 【WC2008】bzoj2595 游览计划
- Bzoj2595: [Wc2008]游览计划
- bzoj2595 [Wc2008]游览计划
- bzoj2595 [Wc2008]游览计划
- Bzoj2595: [Wc2008]游览计划
- BZOJ2595:[Wc2008]游览计划——题解(插头dp)
- BZOJ 2595: [Wc2008]游览计划(斯坦纳树)
- 【bzoj2595】[Wc2008]游览计划 斯坦纳树
- bzoj 2595 : [Wc2008]游览计划
- 【BZOJ 2595】【WC 2008】游览计划
- bzoj 2595 [Wc2008]游览计划(斯坦纳树)
- 【BZOJ 2595】2595: [Wc2008]游览计划 (状压DP+spfa,斯坦纳树?)
- BZOJ 2595: [Wc2008]游览计划 [DP 状压 斯坦纳树 spfa]【学习笔记】
- BZOJ 2595 [Wc2008]游览计划