【题解】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个点. 可以发现我们利用克鲁斯 ...
随机推荐
- mongodb的windows系统下安装
先下载安装包,地址有下面两个,按需选择吧. https://www.mongodb.com/download-center/v2/community https://www.mongodb.org/d ...
- mongodb的高级查询
db的帮助文档 输入:db.help(); db.AddUser(username,password[, readOnly=false]) 添加用户 db.auth(usrename,passwor ...
- mysql新增和更新表从已有数据库里面获取的sql语句
在mysql数据库从已有数据库表插入数据到另一表的sql例子 insert into c(`name`) select name from b; 在mysql数据库从已有数据库表更新数据到另一表的sq ...
- Python特别low的一个文字游戏
闲来无事 ,调侃舍友的游戏 import os class Role(): def __init__(self,name,sex,fighting): self.name=name self.sex= ...
- struts2学习
struts2是一种基于mvc模式的轻量级web框架,它本质上相当于一个servlet,在mvc设计模式中,struts2作为控制器(Controller)来建立模型与视图的数据交互,struts2采 ...
- (数据科学学习手札34)多层感知机原理详解&Python与R实现
一.简介 机器学习分为很多个领域,其中的连接主义指的就是以神经元(neuron)为基本结构的各式各样的神经网络,规范的定义是:由具有适应性的简单单元组成的广泛并行互连的网络,它的组织能够模拟生物神经系 ...
- UVA - 1606 Amphiphilic Carbon Molecules 极角扫描法
题目:点击查看题目 思路:这道题的解决思路是极角扫描法.极角扫描法的思想主要是先选择一个点作为基准点,然后求出各点对于该点的相对坐标,同时求出该坐标系下的极角,按照极角对点进行排序.然后选取点与基准点 ...
- atlas+mysql主主集群实现读写分离
atlas+mysql主主集群实现读写分离 前言: 目前线上系统数据库采用的是主主架构.其中一台主仅在故障时切换使用,(仅单台服务器对外提供服务,当一台出现问题,切换至另一台).该结构很难支撑较大并 ...
- springmvc 配置多视图(jsp,freemarker,HTML等)
SpringMVC 的 Controller 可以返回各种各样的视图.比如 JSP, JSON, Velocity, FreeMarker, XML, PDF, Excel, 还有Html字符流 等等 ...
- axios应用
Skip to content Features Business Explore Marketplace Pricing Sign in or Sign up Watch929 St ...