最小生成树是最小斯坦纳树的一种特殊情况

最小生成树是在给定的点集和边中寻求最短网络使所有点连通

而最小斯坦纳树允许在给定点外增加额外的点,使生成的最短网络开销最小

BZOJ2595

题意是给定一个棋盘图。告诉你景点的位置

然后让你在一些格子上放置指定数量的志愿者使得景点之间可以连通

问你最少需要派遣多少枚志愿者

典型斯坦纳树问题

令f[i][j][k]表示已经连接的景点的集合为k时,包含点a[i][j]的最小值

集合k的引入标志着这是一种状压DP

即以(i,j)为根时,景点集合为k时的斯坦纳树。然后有两种转移

1.由两个子集合并得到集合k,即f[i][j][k]=f[i][j][x]+f[i][j][y]-a[i][j],x|y=k(用景点枚举子集)

2.由根的转移得到,即f[i][j][k]=f[x][y][k]+a[i][j],其中(i,j)和(x,y)相邻(最短路直接SPFA,同层之间的转移有环?)

 #include<cstdio>
#include<queue>
//#include<iostream>
using namespace std;
const int INF=;
const int maxn=;
const int maxm=;
int n,m,K;
int bin[];
bool inq[maxn][maxm],vis[maxn][maxm];
int a[maxn][maxm];
int f[maxn][maxm][];
int dx[]={,,,-};
int dy[]={,-,,};
queue<pair<int,int> > q;
struct Data
{
int fit,sed,thd;
}pre[maxn][maxm][];
inline int read()
{
int x=;char ch=getchar();
while(ch>''||ch<'') ch=getchar();
while(ch>=''&&ch<='') {x=x*+ch-'';ch=getchar();}
return x;
}
void spfa(int sta)
{
//cout<<"###"<<sta<<endl;
while(!q.empty())
{
int x=q.front().first,y=q.front().second;
inq[x][y]=;q.pop();
//cout<<x<<" "<<y<<endl;
for(int k=;k<;k++)
{
int nx=x+dx[k],ny=y+dy[k];
if(x<||y<||x>n||y>m) continue;
if(f[nx][ny][sta]>f[x][y][sta]+a[nx][ny])
{
f[nx][ny][sta]=f[x][y][sta]+a[nx][ny];
pre[nx][ny][sta]=(Data){x,y,sta};
if(!inq[nx][ny])
{
q.push(make_pair(nx,ny));
inq[nx][ny]=;
}
}
}
}
}
void dfs(int x,int y,int sta)
{
if(x>INF||pre[x][y][sta].thd==) return;
vis[x][y]=;
Data t=pre[x][y][sta];
dfs(t.fit,t.sed,t.thd);
if(t.fit==x&&t.sed==y) dfs(x,y,sta-t.thd);
}
int main()
{
bin[]=;
for(int i=;i<;i++) bin[i]=bin[i-]<<;
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++;
}
//令f[i][j][k]表示已经连接的景点的集合为k时
//包含点a[i][j]的最小值
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
for(int k=;k<bin[K];k++)
f[i][j][k]=pre[i][j][k].fit=INF;
K=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
if(a[i][j]==)
f[i][j][bin[K]]=,K++;
//最初始是one-hot,集合中只有自己景点
for(int sta=;sta<bin[K];sta++)
{
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
for(int s=sta&(sta-);s;s=sta&(s-))
{
int t=f[i][j][s]+f[i][j][sta-s]-a[i][j];
if(t<f[i][j][sta])
{
f[i][j][sta]=t;
pre[i][j][sta]=(Data){i,j,s};
}
}
if(f[i][j][sta]<INF)
q.push(make_pair(i,j)),inq[i][j]=;
}
}
spfa(sta);
}
int x,y;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
if(a[i][j]==)
{
x=i;y=j;break;
}
dfs(x,y,bin[K]-);
printf("%d\n",f[x][y][bin[K]-]);
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
if(a[i][j]==) printf("x");
else if(vis[i][j]) printf("o");
else printf("_");
}
puts("");
}
return ;
}

这个题写完之后有一种莫名的打击感

动态规划:状压DP-斯坦纳树的更多相关文章

  1. luogu4294 [WC2008]游览计划(状压DP/斯坦纳树)

    link 题目大意:给定一个网格图,有些点是关键点,选择格点有代价,求把所有关键点联通的最小代价 斯坦纳树模板题 斯坦纳树问题:给定一个图结构,有一些点是关键点,求把这些关键点联通的最小代价e 斯坦纳 ...

  2. [BZOJ4006][JLOI2015]管道连接 状压dp+斯坦纳树

    4006: [JLOI2015]管道连接 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1020  Solved: 552[Submit][Statu ...

  3. 状态压缩动态规划 状压DP

    总述 状态压缩动态规划,就是我们俗称的状压DP,是利用计算机二进制的性质来描述状态的一种DP方式 很多棋盘问题都运用到了状压,同时,状压也很经常和BFS及DP连用,例题里会给出介绍 有了状态,DP就比 ...

  4. 动态规划---状压dp

    状压dp,就是把动态规划之中的一个个状态用二进制表示,主要运用位运算. 这里有一道例题:蓝书P639猛兽军团1 [SCOI2005]互不侵犯 题目: 题目描述 在N×N的棋盘里面放K个国王,使他们互不 ...

  5. 状态压缩动态规划(状压DP)详解

    0 引子 不要999,也不要888,只要288,只要288,状压DP带回家.你买不了上当,买不了欺骗.它可以当搜索,也可以卡常数,还可以装B,方式多样,随心搭配,自由多变,一定符合你的口味! 在计算机 ...

  6. 【状压dp】Trie 树 @中山纪念中学20170304

    目录 Trie 树 PROBLEM 题目描述 输入 输出 样例输入 样例输出 SOLUTION CODE Trie 树 PROBLEM 题目描述 字母(Trie)树是一个表示一个字符串集合中所有字符串 ...

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

    题目链接 f[i][s]表示以i为根节点,当前关键点的连通状态为s(每个点是否已与i连通)时的最优解.i是枚举得到的根节点,有了根节点就容易DP了. 那么i为根节点时,其状态s的更新为 \(f[i][ ...

  8. HDU.3311.Dig The Wells(DP 斯坦纳树)

    题目链接 \(Description\) 有n座庙.一共n+m个点,可以在任意一些点修建水井,不同位置花费不同:也可以某些点之间连无向边共享水.求使n座庙都有水的最小花费. \(Solution\) ...

  9. bzoj 4006 [JLOI2015]管道连接(斯坦纳树+状压DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4006 [题意] 给定n点m边的图,连接边(u,v)需要花费w,问满足使k个点中同颜色的 ...

随机推荐

  1. Android Stadio调试gradle 插件 || Android Stadio 远程调试 || Anroid APT调试

    有时候,自己开发了gralde插件,想调试一下.毕竟打印log 成本太高.效率太低.怎么做呢? 第一种方法: 1.执行gradlew 命令的时候,加上几个参数:-Dorg.gradle.debug=t ...

  2. 破解PHPStrom 10 and Pycharm

    注册时选择 License server http://idea.lanyus.com/ 然后点击OK Pycharm -- License server http://idea.lanyus.com ...

  3. fiddler之弱网测试

    今天就说一下如何使用fiddler做弱网测试 1.首先要把手机的代理打开,这就不多讲了哈,不懂得话请点传送门:https://www.cnblogs.com/fuxinxin/p/9146693.ht ...

  4. cocos2d-x 键盘和鼠标事件

    出了菜单可以响应用户事件外,cocos2d中的层(Layer)也可以响应事件.层能够自动响应窗口事件,这些事件主要是键盘和鼠标事件,cocos2d中事件处理是通过Pyglet的事件处理完成的. 1.键 ...

  5. Python网络编程(进程池、进程间的通信)

    线程池的原理:        线程池是预先创建线程的一种技术.线程池在还没有任务到来之前,        创建一定数量的线程,放入空闲队列中.这些线程都是处于睡眠状态,        即均为启动,不消 ...

  6. String 将GBK转UTF-8

    public void transfer(String xml) throws Exception { return new String(xml.getBytes("gbk"), ...

  7. 杜绝网上压根没测过就乱写之 《oracle mybatis 返回自增主键 》

    面试过好多人,包括自己也属于这么一个情况: 遇到问题直接去网上查,一般都可以查到解决方案.其中也包括一些基本的面试资料的答案. 其实有很多答案也都是正确的,但是还是存在一些压根就是胡乱抄来的答案,也不 ...

  8. HDFS伪分布式

    (一).HDFS shell操作 以上已经介绍了如何搭建伪分布式的Hadoop,既然环境已经搭建起来了,那要怎么去操作呢?这就是本节将要介绍的内容: HDFS自带有一些shell命令,通过这些命令我们 ...

  9. Markdown常用的几种语法

    在VScode上面写的,现将代码粘贴如下:(在VScode里运行下即可) # Markdown语法 # Ctrl + k v 打开侧边预览 ## 一.加粗斜体删除线 **这是要加粗的文字** *这是要 ...

  10. Linux SPI总线和设备驱动架构之四:SPI数据传输的队列化

    我们知道,SPI数据传输可以有两种方式:同步方式和异步方式.所谓同步方式是指数据传输的发起者必须等待本次传输的结束,期间不能做其它事情,用代码来解释就是,调用传输的函数后,直到数据传输完成,函数才会返 ...