[WC2008]游览计划 「斯坦那树模板」
斯坦那树
百度释义
斯坦纳树问题是组合优化问题,与最小生成树相似,是最短网络的一种。最小生成树是在给定的点集和边中寻求最短网络使所有点连通。而最小斯坦纳树允许在给定点外增加额外的点,使生成的最短网络开销最小。
即最小斯坦那树即为并非选择所有的结点,而是选择一部分结点,为保证它们连通,且求解最小开销
题解
斯坦那树模板
发现直接表示点的存在性没有意义
设函数 \(f[i][state]\) 表示:对于点 \(i\),其它结点与其连通情况
那么有两种转移
其一、由其子集转移
\]
之所以要减去 \(value_i\) 是因为会算重
附:枚举子集的方法
for (int sub = state & (state - 1); sub; sub = (sub - 1) & state)
其二、由相邻当前状态下结点转移
\]
发现很像三角形不等式,故考虑 \(SPFA\) 转移
总复杂度 \(O (n3^n + kE2^n)\),\(3^n\) 为枚举子集总复杂度
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN = 10 + 5;
const int MAXM = 1 << 10;
const int INF = 0x3f3f3f3f;
const int NextX[4]= {- 1, 0, 0, 1}, NextY[4]= {0, - 1, 1, 0};
int N, M;
int Map[MAXN][MAXN]= {0};
struct preSt {
int x, y;
int state;
preSt (int fx = 0, int fy = 0, int fs = 0) :
x (fx), y (fy), state (fs) {}
} ;
int f[MAXN][MAXN][MAXM];
preSt pre[MAXN][MAXN][MAXM];
int cnt = 0;
queue<pair<int, int> > que;
void SPFA (int state) {
while (! que.empty()) {
pair<int, int> top = que.front();
que.pop();
int x = top.first, y = top.second;
for (int i = 0; i < 4; i ++) {
int tx = x + NextX[i];
int ty = y + NextY[i];
if (tx < 1 || tx > N || ty < 1 || ty > M)
continue;
if (f[x][y][state] + Map[tx][ty] < f[tx][ty][state]) {
f[tx][ty][state] = f[x][y][state] + Map[tx][ty];
pre[tx][ty][state] = preSt (x, y, state);
que.push(make_pair (tx, ty));
}
}
}
}
int tag[MAXN][MAXN]= {0};
void traceback (int x, int y, int state) {
if (! x || ! y)
return ;
tag[x][y] = 1;
preSt pr = pre[x][y][state];
traceback (pr.x, pr.y, pr.state);
if (pr.x == x && pr.y == y)
traceback (pr.x, pr.y, state - pr.state);
}
int getnum () {
int num = 0;
char ch = getchar ();
while (! isdigit (ch))
ch = getchar ();
while (isdigit (ch))
num = (num << 3) + (num << 1) + ch - '0', ch = getchar ();
return num;
}
int main () {
memset (f, 0x3f, sizeof (f));
N = getnum (), M = getnum ();
int px, py;
for (int i = 1; i <= N; i ++)
for (int j = 1; j <= M; j ++) {
Map[i][j] = getnum ();
if (! Map[i][j]) {
cnt ++, f[i][j][1 << (cnt - 1)] = 0;
px = i, py = j;
}
}
int limit = (1 << cnt) - 1;
for (int state = 1; state <= limit; state ++) {
for (int i = 1; i <= N; i ++)
for (int j = 1; j <= M; j ++) {
for (int sub = state & (state - 1); sub; sub = (sub - 1) & state) // from subset
if (f[i][j][sub] + f[i][j][state - sub] - Map[i][j] < f[i][j][state]) {
f[i][j][state] = f[i][j][sub] + f[i][j][state - sub] - Map[i][j];
pre[i][j][state] = preSt (i, j, sub);
}
if (f[i][j][state] < INF)
que.push(make_pair (i, j));
}
SPFA (state); // from other nodes
}
traceback (px, py, limit);
printf ("%d\n", f[px][py][limit]);
for (int i = 1; i <= N; i ++) {
for (int j = 1; j <= M; j ++) {
if (! Map[i][j])
putchar ('x');
else {
tag[i][j] ? putchar ('o') : putchar ('_');
}
}
puts ("");
}
return 0;
}
/*
4 4
0 1 1 0
2 5 5 1
1 5 5 1
0 1 1 0
*/
[WC2008]游览计划 「斯坦那树模板」的更多相关文章
- BZOJ_2595_[Wc2008]游览计划_斯坦纳树
BZOJ_2595_[Wc2008]游览计划_斯坦纳树 题意: 分析: 斯坦纳树裸题,有几个需要注意的地方 给出矩阵,不用自己建图,但枚举子集转移时会算两遍,需要减去当前点的权值 方案记录比较麻烦,两 ...
- BZOJ2595 Wc2008 游览计划 【斯坦纳树】【状压DP】*
BZOJ2595 Wc2008 游览计划 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个 ...
- 【BZOJ2595_洛谷4294】[WC2008]游览计划(斯坦纳树_状压DP)
上个月写的题qwq--突然想写篇博客 题目: 洛谷4294 分析: 斯坦纳树模板题. 简单来说,斯坦纳树问题就是给定一张有边权(或点权)的无向图,要求选若干条边使图中一些选定的点连通(可以经过其他点) ...
- bzoj 2595 [Wc2008]游览计划(斯坦纳树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2595 [题意] 给定N*M的长方形,选最少权值和的格子使得要求的K个点连通. [科普] ...
- BZOJ2595 WC2008游览计划(斯坦纳树)
斯坦纳树板子题. 考虑状压dp,设f[i][j][S]表示当前在点(i,j)考虑转移,其所在的联通块包含的关键点集(至少)为S的答案. 转移时首先枚举子集,有f[i][j][S]=min{f[i][j ...
- [WC2008]游览计划(斯坦纳树)
[Luogu4294] 题解 : 斯坦纳树 \(dp[i][j]\) 表示以\(i\)号节点为根,当前状态为\(j\)(与\(i\)连通的点为\(1\)) 当根\(i\)不改变时状态转移方程是: \( ...
- BZOJ.2595.[WC2008]游览计划(DP 斯坦纳树)
题目链接 f[i][s]表示以i为根节点,当前关键点的连通状态为s(每个点是否已与i连通)时的最优解.i是枚举得到的根节点,有了根节点就容易DP了. 那么i为根节点时,其状态s的更新为 \(f[i][ ...
- 【BZOJ2595】[Wc2008]游览计划 斯坦纳树
[BZOJ2595][Wc2008]游览计划 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为 ...
- 【BZOJ 2595】2595: [Wc2008]游览计划 (状压DP+spfa,斯坦纳树?)
2595: [Wc2008]游览计划 Time Limit: 10 Sec Memory Limit: 256 MBSec Special JudgeSubmit: 1572 Solved: 7 ...
随机推荐
- NetFPGA Demo ——reference_nic_nf1_cml
NetFPGA Demo --reference_nic_nf1_cml 实验平台 OS:deepin 15.4 开发板:NetFPGA_1G_CML 实验过程 从NetFPGA-1G-CML从零开始 ...
- Spring之注入复杂类型属性
注入类: package helloworld; import java.util.List; import java.util.Map; import java.util.Properties; p ...
- sql server 小技巧 集锦
sql server 小技巧(1) 导入csv数据到sql server sql server 小技巧(2) 删除sql server中重复的数据 sql server 小技巧(3) SQL Serv ...
- GO进程调度相关源码学习
启动流程 procresize流程 malloc.go Memory allocator sizeclass.go span按大小区分的 类型定义 mbitmap.go type and heap b ...
- NOIP2017 列队——动态开点线段树
Description: Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有n×m名学生,方阵的行数为 ...
- java 7 升级后,控制面板里找不到java图标了
如果电脑里只装了jre的情况下,好像从java 7 update 9开始,通过java自动升级程序完成升级后,控制面板里的java图标就不见了. 只好重新从java.sun.com上下载最新版的jre ...
- linux中awk工具的使用(转载)
awk是一个非常好用的数据处理工具.相较于sed常常一整行处理,awk则比较倾向于一行当中分成数个“字段”处理,awk处理方式如下: $ awk '条件类型1{动作1} 条件类型2{动作2} ...' ...
- 无焦点下获取条码枪返回值的Hook(再次改良版)
针对上一个版本再次改良,上除掉无用代码,新手绝对可以看懂! using System; using System.Collections.Generic; using System.Linq; usi ...
- 安装R和Rstudio
安装R和Rstudio 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.安装R编程语言 1.登录下载网站 https://cran.r-project.org/ 2.点击下载链 ...
- vim文本删除方法 Linux
1,先打开某个文件: vim filename 2,转到文件结尾 在命令模式输入 G 3,转到10行 在命令模式输入 10G 4,删除所有内容:先用G 转到文件尾,然后使用下面命令: :1, .d ...