【题解】WC2008游览计划
写的第一道斯坦纳树的题目。斯坦纳树在信息学中的应用一般为:在\(n\)个点之间给定\(k\)条边并相应的边权,求在保证给定\(m\)个点联通的条件下的最小边权和。解决此类问题的方法即为SPFA + 状压DP。参考论文:姜碧野 《SPFA的优化与应用》
我们用\(dp[u][S]\)表示以u为根,联通状态为S(01状态)的最小权值。以u为根:最优解必然构成一棵最小生成树。那么有两种转移方式:
\(dp[u][S] = dp[u][k'] + dp[u][k''] - a[u] \left ( S = k' + k'' \right )\)
这一个可以理解为\(u\)点为树上的一个分叉点,由该点分别走向两侧,一侧联通\(k'\)集合,一侧联通\(k''\)集合,通过\(u\)点联通成\(S\)集合。这种转移比较好处理,只需枚举子集即可。
\(dp[u][S] = dp[v][S] + w[u][v]\)
这里是从\(u\)点走向了\(v\)点,联通了这两个集合,通过\(u -> v\)这条边来连接。这一种情况就比较复杂了:\(u\)可以转移到\(v\),\(v\)也可以转移到\(u\),但这个方程式却给了我们一点联想:好像很像是最短路中的松弛操作呀。其满足三角形不等式,虽然图中有环的存在,但最优解并不构成环。所以我们用SPFA来进行这一部分的DP。
在本题中,\(f[i][j][S]\)代表以点\(i, j\)为根,联通状态为\(S\)的最优权值。
#include <bits/stdc++.h>
using namespace std;
#define maxn 12
#define maxm (1 << 10) + 2
#define INF 1e9
int n, m, K, f[maxn][maxn][maxm];
int a[maxn][maxn], bin[maxn];
int dx[] = {, , , -}, dy[] = {, -, , };
bool vis[maxn][maxn]; struct node
{
int x, y;
node (int _x = , int _y = ) { x = _x, y = _y; }
};
queue <node> q; struct Path
{
int x, y, s;
Path (int _x = , int _y = , int _s = ) { x = _x, y = _y, s = _s; }
}path[maxn][maxn][maxm]; int read()
{
int x = , k = ;
char c;
c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} void init()
{
bin[] = ;
for(int i = ; i < ; i ++) bin[i] = bin[i - ] << ;
} void SPFA(int S)
{
while(!q.empty())
{
int x = q.front().x, y = q.front().y;
vis[x][y] = , q.pop();
for(int k = ; k < ; k ++)
{
int X = x + dx[k], Y = y + dy[k];
if(X < || Y < || X > n || Y > m) continue;
if(f[X][Y][S] > f[x][y][S] + a[X][Y])
{
f[X][Y][S] = f[x][y][S] + a[X][Y];
path[X][Y][S] = Path(x, y, S);
if(!vis[X][Y]) q.push(node(X, Y)), vis[X][Y] = ;
}
}
}
} #define t path[x][y][S]
void dfs(int x, int y, int S)
{
if(x > INF || !t.s) return;
vis[x][y] = ; dfs(t.x, t.y, t.s);
if(t.x == x || t.y == y) dfs(x, y, S ^ t.s);
}
#undef t void Solve()
{
for(int S = ; S < bin[K]; SPFA(S ++))
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++)
{
for(int k = S & (S - ); k; k = (k - ) & S)
{
int t = f[i][j][k] + f[i][j][S ^ k] - a[i][j];
if(t < f[i][j][S]) { f[i][j][S] = t; path[i][j][S] = Path(i, j, k); }
}
if(f[i][j][S] != INF) { q.push(node(i, j)); vis[i][j] = ; }
}
} void Get_ans()
{
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++)
if(!a[i][j])
{
dfs(i, j, bin[K] - );
printf("%d\n", f[i][j][bin[K] - ]);
return;
}
} int main()
{
init();
n = read(), m = read();
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++)
{
a[i][j] = read();
if(!a[i][j]) K ++;
}
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++)
for(int k = ; k < bin[K]; k ++)
f[i][j][k] = path[i][j][k].x = INF;
K = ;
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++)
if(!a[i][j]) f[i][j][bin[K]] = , K ++;
Solve();
memset(vis, , sizeof(vis));
Get_ans();
for(int i = ; i <= n; i ++, putchar('\n'))
for(int j = ; j <= m; j ++)
if(!a[i][j]) putchar('x');
else if(vis[i][j]) putchar('o');
else putchar('_');
return ;
}
【题解】WC2008游览计划的更多相关文章
- 【BZOJ2595】[Wc2008]游览计划 斯坦纳树
[BZOJ2595][Wc2008]游览计划 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为 ...
- 【LG4294】[WC2008]游览计划
[LG4294][WC2008]游览计划 题面 洛谷 bzoj 题解 斯坦纳树板子题. 斯坦纳树的总结先留个坑. 代码 #include <iostream> #include <c ...
- BZOJ_2595_[Wc2008]游览计划_斯坦纳树
BZOJ_2595_[Wc2008]游览计划_斯坦纳树 题意: 分析: 斯坦纳树裸题,有几个需要注意的地方 给出矩阵,不用自己建图,但枚举子集转移时会算两遍,需要减去当前点的权值 方案记录比较麻烦,两 ...
- [WC2008]游览计划 解题报告
[WC2008]游览计划 斯坦纳树板子题,其实就是状压dp 令\(dp_{i,s}\)表示任意点\(i\)联通关键点集合\(s\)的最小代价 然后有转移 \[ dp_{i,S}=\min_{T\in ...
- bzoj2595 / P4294 [WC2008]游览计划
P4294 [WC2008]游览计划 斯坦纳树 斯坦纳树,是一种神奇的树.它支持在一个连通图上求包含若干个选定点的最小生成树. 前置算法:spfa+状压dp+dfs(大雾) 我们设$f[o][P]$为 ...
- 【BZOJ2595】 [Wc2008]游览计划
BZOJ2595 [Wc2008]游览计划 Solution 考虑这是一个最小费用连通性的问题,既然大家都说这是什么斯坦纳树那就是的吧... 所以我们肯定可以这样设一个dp状态: \(dp_{i,j, ...
- 【BZOJ 2595】2595: [Wc2008]游览计划 (状压DP+spfa,斯坦纳树?)
2595: [Wc2008]游览计划 Time Limit: 10 Sec Memory Limit: 256 MBSec Special JudgeSubmit: 1572 Solved: 7 ...
- BZOJ2595 Wc2008 游览计划 【斯坦纳树】【状压DP】*
BZOJ2595 Wc2008 游览计划 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个 ...
- [bzoj2595][WC2008]游览计划/[bzoj5180][Baltic2016]Cities_斯坦纳树
游览计划 bzoj-2595 wc-2008 题目大意:题目链接.题目连接. 注释:略. 想法:裸题求斯坦纳树. 斯坦纳树有两种转移方式,设$f[s][i]$表示联通状态为$s$,以$i$为根的最小代 ...
- luogu P4294 [WC2008]游览计划
LINK:游览计划 斯坦纳树例题. 斯坦纳树是这样一类问题:带权无向图上有K个关键点 求出包含这K个点的最小生成树. 也就是说 求最小生成树 但是 并不是整张图 仅限于K个点. 可以发现我们利用克鲁斯 ...
随机推荐
- Java小功能大杂烩
生成UUID: import java.util.UUID; public class ProductUUID { // 随机返回前十位的UUID public static String getUU ...
- SHOPEX快递单号查询插件圆通V8.2专版
SHOPEX快递物流单号查询插件特色 本SHOPEX快递物流单号跟踪插件提供国内外近2000家快递物流订单单号查询服务例如申通快递.顺丰快递.圆通快递.EMS快递.汇通快递.宅急送快递.德邦物流.百世 ...
- MIP缓存加速原理 MIP不仅仅只是CDN
什么是MIP?我想我们现在都知道.可是你真的了解MIP吗?MIP加速原理是什么?MIP 是用 CDN 做加速的么?准确答案是:是,但不只是. 很多人并认为MIP百度排名会靠前,甚至权重会提高?作为一个 ...
- STM32CubeMx配置正交编码器遇到的问题
配置时参考了这个哥们的方法: http://www.eemaker.com/stm32cubemx-encoder.html 然后我的配置是这样的 配置是没有问题. 调用时出现了问题. 由于配置完了, ...
- python中使用空格还是使用 Tab键缩进的建议
对于程序员来说,其实Tab和空格远远不只是“立场”问题那么简单. 在不同的编辑器里tab的长度可能不一致,所以在一个编辑器里用tab设置缩进后,在其它编辑器里看可能缩进就乱了.空格不会出现这个问题,因 ...
- 08 datetime与logging模块(进阶)
datetime与logging模块 阶段一:日期与时间 1.datetime 模块中 主要类: 类名 功能说明 date 日期对象,常用的属性有year, month, day time 时间对象h ...
- ctf题目writeup(3)
题目地址: https://www.ichunqiu.com/battalion 1. 这个是个mp3,给的校验是为了下载下来的. 下来之后丢进audicity中 放大后根据那个音块的宽度来确定是 . ...
- nodejs环境变量配置
步骤 创建文件夹:安装包 配置环境变量: export NODE_HOME=/root/安装包/node-v7.6.0-linux-x64 export PATH=$NODE_HOME/bin:$PA ...
- Python tips(
(此文是在实际工程中遇到的一些小问题,给予解决和整理.解决方法大多来自网上零散的文章.有一个系统化的Python问题解决方案,来自<Python 3 学习笔记>雨痕著,其中对Python的 ...
- R语言学习笔记(七): 排序函数:sort(), rank(), order()
sort() sort()函数直接对函数进行排序,并返回排序结果. > a <- c(12,4,6,5) > sort(a) [1] 4 5 6 12 rank() rank()函数 ...