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

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

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

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. vs2013中将复制过来的文件或文件夹显示到解决方案管理

    先将文件夹和文件复制到VS程序所在的位置,在VS2013解决方案资源管理器中找到这些文件所在的上一级文件夹,先将那个上层文件夹收缩起来,然后再点击解决方案资源管理器上的“显示所有文件”按纽,展开这个文 ...

  2. Linux篇:因为修改了/etc/sudoers 文件的权限导致的问题

    因为想要把sudo变成免密码所以就查了网上的教程.说是要修改/etc/sudoers文件,但是修改的时候发现这个文件是只读, 所以就 /etc/sudoers 结果就导致了接下来用sudo的时候提示如 ...

  3. 5.hbase表新增数据同步之add_peer

    一.前提主从集群之间能互相通讯: 二.在cluster1上(源集群):  1.查看集群已开启的peers hbase(main):011:0> list_peers PEER_ID CLUSTE ...

  4. 获取单片机唯一id(stm32获取单片机唯一id)

    stm32唯一id: 不同型号的stm32单片机,id不在同一地址上!具体地址可以通过用户手册中的Device electronic signature>Unique device ID reg ...

  5. nginx+tomcat 反向代理 负载均衡配置

    1.nginx的安装和配置见:http://www.cnblogs.com/ll409546297/p/6795362.html 2.tomcat部署项目到对应的服务器上面并启动,不详解 3.在ngi ...

  6. 25、react入门教程

    0. React介绍 0.1 什么是React? React(有时称为React.js 或ReactJS)是一个为数据提供渲染HTML视图的开源JavaScript库. 它由FaceBook.Inst ...

  7. QC的使用学习(二)

    今日学习清单: 1.Quality  Center中左上角选项中(QC 10.0中文版)工具菜单下的自定义中的几个内容,有:用户属性.组.项目用户.模块访问.需求类型.项目列表等.用户属性打开后是对当 ...

  8. Go基础篇【第4篇】: 内置库模块 bufio

    bufio包实现了有缓冲的I/O.它包装一个io.Reader或io.Writer接口对象,创建另一个也实现了该接口,且同时还提供了缓冲和一些文本I/O的帮助函数的对象. 即:为了解决CPU与磁盘IO ...

  9. POJ 3076 / ZOJ 3122 Sudoku(DLX)

    Description A Sudoku grid is a 16x16 grid of cells grouped in sixteen 4x4 squares, where some cells ...

  10. 使用SetOperations(无序)操作redis

    方法 c参数 s说明 Long add(K key, V... values); K key:集合key V... values:key对应的值 向集合中添加一个或多一个元素 Long remove( ...