BZOJ.2595.[WC2008]游览计划(DP 斯坦纳树)
f[i][s]表示以i为根节点,当前关键点的连通状态为s(每个点是否已与i连通)时的最优解。i是枚举得到的根节点,有了根节点就容易DP了。
那么i为根节点时,其状态s的更新为 \(f[i][s]=min\{f[i][s']+f[i][\complement_{s}s']-cost[i]\},s'\in s\)(枚举子集s'后,显然只需要s'的补集。减cost[i]是因为两种状态都包含,cost[i]算重了)
如果我们想合并入当前连通块一个新的非关键点v并以v为根,那么 \(f[v][s]=min\{f[k][s]+cost[v]\},k,v相邻\)
第一个更新可以按顺序,第二个更新没有明显顺序,但是如果固定状态s,很像SPFA,可类似转移。
输出方案,可以每次转移记录转移前的点与状态s,因为可能是转移点也可能是用子集更新。最后随便找一个关键点开始DFS即可。
复杂度 \(O(n\times 3^k+cE\times 2^k)\)
c为SPFA复杂度中的常数,E为边的数量,但几乎达不到全部边的数量,甚至非常小。\(3^k\)来自于子集的转移\(\sum_{i=1}^nC_n^i\times 2^i\),用二项式展开求一下和。
//2080kb 148ms
#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
#define En(i,j) (i*m+j)//Encode
#define De(w) mp(w/m,w%m)//Decode
#define mp std::make_pair
#define pr std::pair<int,int>
const int N=102,INF=1e9,to[5]={1,0,-1,0,1};
int n,m,cost[N],f[(1<<10)+1][N];//换下了顺序 注意!
pr pre[(1<<10)+1][N];
bool inq[N],vis[N];
std::queue<int> q;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
void SPFA(int *f,pr *pre,int s)
{
while(!q.empty())
{
int now=q.front();
q.pop(), inq[now]=0;
for(int x=now/m,y=now%m,xn,yn,nxt,i=0; i<4; ++i)
if((xn=x+to[i])>=0&&xn<n&&(yn=y+to[i+1])>=0&&yn<m && f[nxt=En(xn,yn)]>f[now]+cost[nxt])
{
f[nxt]=f[now]+cost[nxt], pre[nxt]=mp(now,s);
if(!inq[nxt]) inq[nxt]=1, q.push(nxt);
}
}
}
void DFS(int p,int s)
{
if(!pre[s][p].second) return;//pre.second即 无转移了
vis[p]=1;
if(pre[s][p].first==p) DFS(p,s^pre[s][p].second);
DFS(pre[s][p].first,pre[s][p].second);
}
int main()
{
n=read(), m=read(); int K=0, rt=0;
memset(f,0x3f,sizeof f);
for(int tot=0,i=0; i<n; ++i)
for(int j=0; j<m; ++j,++tot)
{
cost[tot]=read();
if(!cost[tot]) f[1<<(K++)][tot]=0, rt=tot;
}
for(int s=1; s<(1<<K); ++s)
{
for(int i=0; i<n*m; ++i)
{
for(int sub=(s-1)&s; sub; sub=(sub-1)&s)
if(f[s][i]>f[sub][i]+f[sub^s][i]-cost[i])
f[s][i]=f[sub][i]+f[sub^s][i]-cost[i], pre[s][i]=mp(i,sub);
if(f[s][i]<INF) q.push(i), inq[i]=1;//多起点,inq[]还是不能省啊
}
SPFA(f[s],pre[s],s);
}
printf("%d\n",f[(1<<K)-1][rt]);
DFS(rt,(1<<K)-1);
for(int i=0,tot=0; i<n; ++i,putchar('\n'))
for(int j=0; j<m; ++j,++tot)
if(!cost[tot]) putchar('x');
else putchar(vis[tot]?'o':'_');
return 0;
}
BZOJ.2595.[WC2008]游览计划(DP 斯坦纳树)的更多相关文章
- bzoj 2595 [Wc2008]游览计划(斯坦纳树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2595 [题意] 给定N*M的长方形,选最少权值和的格子使得要求的K个点连通. [科普] ...
- BZOJ_2595_[Wc2008]游览计划_斯坦纳树
BZOJ_2595_[Wc2008]游览计划_斯坦纳树 题意: 分析: 斯坦纳树裸题,有几个需要注意的地方 给出矩阵,不用自己建图,但枚举子集转移时会算两遍,需要减去当前点的权值 方案记录比较麻烦,两 ...
- BZOJ 2595: [Wc2008]游览计划 [DP 状压 斯坦纳树 spfa]【学习笔记】
传送门 题意:略 论文 <SPFA算法的优化及应用> http://www.cnblogs.com/lazycal/p/bzoj-2595.html 本题的核心就是求斯坦纳树: Stein ...
- BZOJ2595 Wc2008 游览计划 【斯坦纳树】【状压DP】*
BZOJ2595 Wc2008 游览计划 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个 ...
- 【BZOJ2595_洛谷4294】[WC2008]游览计划(斯坦纳树_状压DP)
上个月写的题qwq--突然想写篇博客 题目: 洛谷4294 分析: 斯坦纳树模板题. 简单来说,斯坦纳树问题就是给定一张有边权(或点权)的无向图,要求选若干条边使图中一些选定的点连通(可以经过其他点) ...
- 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+SPFA? 用来学习斯坦纳树的模板. 大概就是用二进制来表示树包含的点,然后用跟几点表示树的形态. 更新分为两种,一种是合并两个子集,一种是换根,换根用SPFA迭代即 ...
- bzoj:2595: [Wc2008]游览计划
Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点:否则表示控制该方块至少需要的志愿者数 ...
随机推荐
- np.linespace使用方法
np.linespace用法 觉得有用的话,欢迎一起讨论相互学习~Follow Me 生成指定范围内指定个数的一维数组 def linspace(start, stop, num=50, endpoi ...
- vs2015的visual assist X options安装过程
1.安装VA_X之前,请先关闭VS2015程序. 2.下载VA_X_Setup2048.exe和VAX2048破解补丁.zip. 3.双击运行VA_X_Setup2048.exe文件,安装完成后出现 ...
- SQL记录-PLSQL运算符
PL/SQL运算符 运算符是一个符号,告诉编译器执行特定的数学或逻辑操作. PL/SQL语言有丰富的内置运算符,运算符提供的以下几种类型: 算术运算符 关系运算符 比较运算符 逻辑运算符 字符串运算符 ...
- SpringBoot入门Demo(Hello Word Boot)
Spring Boot 是由Pivotal团队提供的全新框架,其设计目的是用来简化新的Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置. ...
- Kafka 温故(一):Kafka背景及架构介绍
一.Kafka简介 Kafka是分布式发布-订阅消息系统.它最初由LinkedIn公司开发,使用Scala语言编写,之后成为Apache项目的一部分.Kafka是一个分布式的,可划分的,多订阅者,冗余 ...
- Git常见错误处理
如果输入$ Git remote add origin git@github.com:djqiang(github帐号名)/gitdemo(项目名).git 提示出错信息:fatal: remo ...
- python selenium - web自动化环境搭建
前提: 安装python环境. 参考另一篇博文:https://www.cnblogs.com/Simple-Small/p/9179061.html web自动化:实现代码驱动浏览器进行点点点的操作 ...
- nested exception is com.svorx.core.dao.PersistenceException
在quartz定时执行任务的时候,hibernate报错,在只读事务中进行了update语句: [ERROR] 2018/08/03 10:35:00,827 org.quartz.core.JobR ...
- casperjs get开头的几个dom操作使用
getCurrentUrl() Signature: getCurrentUrl() Retrieves current page URL. Note that the url will be url ...
- Linux6.5 安装Python3.X(转载)
1.获取Python 3.6.3 通过官网https://www.python.org/downloads/下载Python 3.4.3源码: 源码获取命令如下:wget https://www.py ...