题目链接

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. ngx_lua_API 指令详解(六)ngx.thread.spawn、ngx.thread.wait、ngx.thread.kill介绍

    摘要:通过lua-nginx-module中的ngx.thread同时执行多个任务. ngx_lua中访问多个第三方服务 ngx_lua中提供了ngx.socket API,可以方便的访问第三方网络服 ...

  2. javascript鼠标拖拽的那些事情

    <html> <head> <title>javascript鼠标拖拽的那些事情</title> <meta http-equiv="C ...

  3. ASP.NET生成二维码

    下面使用ThoughtWorks.QRCode.dll这个类库,实现生成二维码 使用时需要增加:下面三个命名空间 using ThoughtWorks.QRCode.Codec; using Thou ...

  4. 【三分钟视频教程】iOS开发中 Xcode 报 apple-o linker 错误的#解决方案#

      [三分钟视频教程]iOS开发中 Xcode 报 apple-o linker 错误的#解决方案#   同样的道理,指向同一库文件的代码语句如果重复书写,即使重复书写所在的文件名字不同,同样会造成这 ...

  5. iOS 处理缓存的三种方法

    缓存处理是个相当头疼的事情,要根据需要综合应用不同的策略.总的来说有以下几种情况: 1.URL缓存,例如社交应用的帖子浏览,要在viewDidAppear:里面进行URL缓存.简单来说就是用NSURL ...

  6. HDU 6395 Sequence 杜教板子题

    题目意思非常明确,就是叫你求第n项,据我们学校一个大佬说他推出了矩阵,但是我是菜鸡,那么肯定是用简单的方法水过啦!我们先p^(1/2)的复杂度处理出i=[i,p]范围内的所有种类的(int)(p/i) ...

  7. Linux 串口、usb转串口驱动分析(2-2) 【转】

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26807463&id=4186852 Linux 串口.usb转 ...

  8. RESET MASTER和RESET SLAVE使用场景和说明【转】

    [前言]在配置主从的时候经常会用到这两个语句,刚开始的时候还不清楚这两个语句的使用特性和使用场景. 经过测试整理了以下文档,希望能对大家有所帮助: [一]RESET MASTER参数 功能说明:删除所 ...

  9. SharePoint 2013 另一个程序正在使用此文件,进程无法访问。 (异常来自 HRESULT:0x80070020)

    环境:SharePoint 2013 + Windows Server 2012 R2 在管理中心新建一个Web Application,端口为:88.顺利创建网站集后,打开访问却提示:无法显示此页 ...

  10. NEERC Southern Subregional 2011

    NEERC Southern Subregional 2011 A - Bonnie and Clyde solution 双指针搞搞就好. 时间复杂度:\(O(n)\) B - Building F ...