动态规划:状压DP-斯坦纳树
最小生成树是最小斯坦纳树的一种特殊情况
最小生成树是在给定的点集和边中寻求最短网络使所有点连通
而最小斯坦纳树允许在给定点外增加额外的点,使生成的最短网络开销最小
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-斯坦纳树的更多相关文章
- luogu4294 [WC2008]游览计划(状压DP/斯坦纳树)
link 题目大意:给定一个网格图,有些点是关键点,选择格点有代价,求把所有关键点联通的最小代价 斯坦纳树模板题 斯坦纳树问题:给定一个图结构,有一些点是关键点,求把这些关键点联通的最小代价e 斯坦纳 ...
- [BZOJ4006][JLOI2015]管道连接 状压dp+斯坦纳树
4006: [JLOI2015]管道连接 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1020 Solved: 552[Submit][Statu ...
- 状态压缩动态规划 状压DP
总述 状态压缩动态规划,就是我们俗称的状压DP,是利用计算机二进制的性质来描述状态的一种DP方式 很多棋盘问题都运用到了状压,同时,状压也很经常和BFS及DP连用,例题里会给出介绍 有了状态,DP就比 ...
- 动态规划---状压dp
状压dp,就是把动态规划之中的一个个状态用二进制表示,主要运用位运算. 这里有一道例题:蓝书P639猛兽军团1 [SCOI2005]互不侵犯 题目: 题目描述 在N×N的棋盘里面放K个国王,使他们互不 ...
- 状态压缩动态规划(状压DP)详解
0 引子 不要999,也不要888,只要288,只要288,状压DP带回家.你买不了上当,买不了欺骗.它可以当搜索,也可以卡常数,还可以装B,方式多样,随心搭配,自由多变,一定符合你的口味! 在计算机 ...
- 【状压dp】Trie 树 @中山纪念中学20170304
目录 Trie 树 PROBLEM 题目描述 输入 输出 样例输入 样例输出 SOLUTION CODE Trie 树 PROBLEM 题目描述 字母(Trie)树是一个表示一个字符串集合中所有字符串 ...
- BZOJ.2595.[WC2008]游览计划(DP 斯坦纳树)
题目链接 f[i][s]表示以i为根节点,当前关键点的连通状态为s(每个点是否已与i连通)时的最优解.i是枚举得到的根节点,有了根节点就容易DP了. 那么i为根节点时,其状态s的更新为 \(f[i][ ...
- HDU.3311.Dig The Wells(DP 斯坦纳树)
题目链接 \(Description\) 有n座庙.一共n+m个点,可以在任意一些点修建水井,不同位置花费不同:也可以某些点之间连无向边共享水.求使n座庙都有水的最小花费. \(Solution\) ...
- bzoj 4006 [JLOI2015]管道连接(斯坦纳树+状压DP)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4006 [题意] 给定n点m边的图,连接边(u,v)需要花费w,问满足使k个点中同颜色的 ...
随机推荐
- 9.Mongodb与python交互
1.与python交互 点击查看官方文档 安装python包 进入虚拟环境 sudo pip install pymongo 或源码安装 python setup.py 引入包pymongo impo ...
- leetcode笔记--1 two-sum
my answer: 出现的问题:倒数第二行and i !=s这种情况没有考虑进去,以后要思考全面些
- OBS源码编译开发
本文来自网易云社区 作者:梁敏 OBS简介 OBS(Open Broadcaster Software)是免费开源的视频录制和直播软件,支持运行在windows,Mac和linux平台.官方链接 ht ...
- 【个人训练】(ZOJ3983)Crusaders Quest
题意分析 和祖玛类似的那种玩法.不过是限定了九个字符,问最好情况下有几次三连碰. 暴力穷举即可.具体的做法是,先把所有"成块"的字符记录下来,然后一个一个删,再继续这样子递归做下去 ...
- SSH公钥认证(码云)
开发者向码云版本库写入最常用到的协议是 SSH 协议,因为 SSH 协议使用公钥认证,可以实现无口令访问,而若使用 HTTPS 协议每次身份认证时都需要提供口令.使用 SSH 公钥认证,就涉及到公钥的 ...
- wirehshark解密IPSEC流量
wireshark解密IPSEC加密过的流量 题目是安恒二月月赛题目:简单的流量分析 1.首先会发现很多esp类型的流量 我们不知道密钥就没有办法解密,猜测密钥肯定是在流量包里面的. 加密流量在786 ...
- android问题笔记集
开发工具:android studio2.2 调试:手机直连调试,版本(android6) 问题1: Error:Unable to start the daemon process. This pr ...
- Dijkstra模板 dj斯特拉
图论里非常常用的dijkstra,自己加了个路径查找,做个模板吧: ; struct Edge { int from,to,dist; Edge(int u, int v, int d):from(u ...
- rcnn caffe matlab 配置完成 14.04 cuda 7.0
http://blog.csdn.net/real_myth/article/details/42672381 各种痛苦.实验室网速还是龟速. 莫名其妙的错误. gcc还降级到4.7,opencv 3 ...
- eniac世界第二台计算机
ENIAC,全称为Electronic Numerical Integrator And Computer,即电子数字积分计算机.ENIAC是世界上第一台通用计算机,也是继ABC(阿塔纳索夫-贝瑞计算 ...