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

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

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

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. 初步学习pg_control文件之二

    接前文:初步认识pg_control文件 继续学习,pg_control文件在何处形成的?是在initdb的时候,运用的函数如下: /* * This func must be called ONCE ...

  2. java使用java.util.Properties读取properties文件的九种方法

    直接上代码: package com.test.test; import java.io.BufferedInputStream; import java.io.FileInputStream; im ...

  3. 【连载】Bootstrap开发漂亮的前端界面之自定义右键菜单

    连载: 1<教你用Bootstrap开发漂亮的前端界面> 2.<Bootstrap开发漂亮的前端界面之实现原理> 网页中的自定义右键菜单越来越普遍,自定义右键菜单可以增强用户体 ...

  4. 通过repcached实现memcached主从复制

    一.环境 服务器A:ubuntu server 12.04(192.168.1.111) 服务器B:ubuntu server 12.04 (47.50.13.111) 二.memcached安装 s ...

  5. Qt C++ 并发,并行,多线程编程系列1 什么是并发

    什么是并发,并发往简单来说就是两个或多个独立的任务同时发生,在我们的生活中也是随处可见.如果把每个人都当作一个独立的任务,那每个人可以相互独立的生活,这就是并发. 在计算机的系统里面,并发一般有两种, ...

  6. 从传统IT快速走向公共云计算

    2年前有篇报道,说Facebook的每个运维同学至少能管理2万台服务器,这在当时的国内互联网引起了很大震动,按照传统IT的理解,每个运维同学能管理200台服务器已经很了不起了. 这些年来云计算发展非常 ...

  7. 九度OJ--Q1164

    import java.util.Scanner; /* * 题目描述: * 任意输入两个9阶以下矩阵,要求判断第二个是否是第一个的旋转矩阵,如果是,输出旋转角度(0.90.180.270),如果不是 ...

  8. mongodb数据库操作之简单查询

    1. 2. 3.修改器 默认一条一条修改 4. 5.查询 6.mysql简单操作

  9. Android stateMachine分析

    StateMachine与State模式的详细介绍可以参考文章:Android学习 StateMachine与State模式 下面是我对于StateMachine的理解: 先了解下消息处理.看下Sta ...

  10. windows apache启动报错

    Windows启动Apache时报错 he requested operation has failed 有可能80端口被占或者项目路径不存在等 首先找到问题原因 cmd--命令端--切换到apach ...