题目链接

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 斯坦纳树)的更多相关文章

  1. bzoj 2595 [Wc2008]游览计划(斯坦纳树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2595 [题意] 给定N*M的长方形,选最少权值和的格子使得要求的K个点连通. [科普] ...

  2. BZOJ_2595_[Wc2008]游览计划_斯坦纳树

    BZOJ_2595_[Wc2008]游览计划_斯坦纳树 题意: 分析: 斯坦纳树裸题,有几个需要注意的地方 给出矩阵,不用自己建图,但枚举子集转移时会算两遍,需要减去当前点的权值 方案记录比较麻烦,两 ...

  3. BZOJ 2595: [Wc2008]游览计划 [DP 状压 斯坦纳树 spfa]【学习笔记】

    传送门 题意:略 论文 <SPFA算法的优化及应用> http://www.cnblogs.com/lazycal/p/bzoj-2595.html 本题的核心就是求斯坦纳树: Stein ...

  4. BZOJ2595 Wc2008 游览计划 【斯坦纳树】【状压DP】*

    BZOJ2595 Wc2008 游览计划 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个 ...

  5. 【BZOJ2595_洛谷4294】[WC2008]游览计划(斯坦纳树_状压DP)

    上个月写的题qwq--突然想写篇博客 题目: 洛谷4294 分析: 斯坦纳树模板题. 简单来说,斯坦纳树问题就是给定一张有边权(或点权)的无向图,要求选若干条边使图中一些选定的点连通(可以经过其他点) ...

  6. BZOJ2595 WC2008游览计划(斯坦纳树)

    斯坦纳树板子题. 考虑状压dp,设f[i][j][S]表示当前在点(i,j)考虑转移,其所在的联通块包含的关键点集(至少)为S的答案. 转移时首先枚举子集,有f[i][j][S]=min{f[i][j ...

  7. [WC2008]游览计划(斯坦纳树)

    [Luogu4294] 题解 : 斯坦纳树 \(dp[i][j]\) 表示以\(i\)号节点为根,当前状态为\(j\)(与\(i\)连通的点为\(1\)) 当根\(i\)不改变时状态转移方程是: \( ...

  8. BZOJ 2595 [Wc2008]游览计划 ——斯坦纳树

    [题目分析] 斯坦纳树=子集DP+SPFA? 用来学习斯坦纳树的模板. 大概就是用二进制来表示树包含的点,然后用跟几点表示树的形态. 更新分为两种,一种是合并两个子集,一种是换根,换根用SPFA迭代即 ...

  9. bzoj:2595: [Wc2008]游览计划

    Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点:否则表示控制该方块至少需要的志愿者数 ...

随机推荐

  1. 数据结构(三)串---KMP模式匹配算法

    (一)定义 由于BF模式匹配算法的低效(有太多不必要的回溯和匹配),于是某三个前辈发表了一个模式匹配算法,可以大大避免重复遍历的情况,称之为克努特-莫里斯-普拉特算法,简称KMP算法 (二)KMP算法 ...

  2. Kafka 温故(一):Kafka背景及架构介绍

    一.Kafka简介 Kafka是分布式发布-订阅消息系统.它最初由LinkedIn公司开发,使用Scala语言编写,之后成为Apache项目的一部分.Kafka是一个分布式的,可划分的,多订阅者,冗余 ...

  3. js 正则学习小记之匹配字符串字面量优化篇

    昨天在<js 正则学习小记之匹配字符串字面量>谈到 个字符,除了第一个 个,只有 个转义( 个字符),所以 次,只有 次成功.这 次匹配失败,需要回溯后用 [^"] 才能匹配成功 ...

  4. android 调用系统照相机拍照后保存到系统相册,在系统图库中能看到

    需求:  调用系统照相机进行拍照,并且保存到系统相册,调用系统相册的时候能看到   系统相册的路径:String cameraPath= Environment.getExternalStorageD ...

  5. MySQL一问一答

    一.问:如果有一张表,里面有个字段为id的自增主键,当已经向表里面插入了10条数据之后,删除了id为8,9,10的数据,再把mysql重启,之后再插入一条数据,那么这条数据的id值应该是多少,是8,还 ...

  6. Java编程的逻辑 (23) - 枚举的本质

    ​本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...

  7. Python Extension 编译问题

    Python 的一大好处是调用C扩展程序相当方便,但是 Windows 下的话,编译器版本是一个大问题.以Python27为例,官方版本时采用VC2008编译的.在setup.py中添加Extensi ...

  8. APIO2018酱油记

    苟比主席树太难了学不会 还是把APIO几天的过程记下来吧...免得忘了 DAY -5 去CTSC的人都走了,机房好冷清...只有我.PSB.yasar.Chlience四个人 CSTC辣么难又辣么贵, ...

  9. js文件的版本控制

    使用grunt完成requirejs的合并压缩和js文件的版本控制   最近有一个项目使用了 requirejs 来解决前端的模块化,但是随着页面和模块的越来越多,我发现我快要hold不住这些可爱的j ...

  10. Orchard学习 02、orchard 路由

    Orchard对mvc路由重新做了包装,重写了asp.net的路由模块 一.路由模块类图 1.路由 Descriptor RouteDescriptor是对常规mvc路由的包装类,它的Route属性就 ...