题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2595

今天刚学了斯坦纳树,还不太会,写一道题练习一下;

参考了博客:http://www.cnblogs.com/lazycal/archive/2013/08/31/bzoj-2595.html

代码也是模仿着写的,感觉有了更深的理解;

总之,大概就是两种转移方式,合并转移枚举子集即可,最短路转移用 spfa;

还要记录一个 pre 用来找到连通块内的点;

用哈希一样的方法把几个数 pack 起来的写法真神奇啊;

说实话还是有点云里雾里,不过成功写出了第一道斯坦纳树的题,感觉很好!

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int const maxn=,inf=0x3f3f3f3f;
int n,m,K,mx,f[maxn][maxn][<<maxn],a[maxn][maxn],pre[maxn][maxn][<<maxn];
int dx[]={,,-,},dy[]={,,,-};
bool vis[maxn][maxn],inq[maxn*maxn];
queue<int>q;
int pack(int i,int j){return i*+j;}
int pack2(int i,int j,int s){return i*+j*+s;}
void unpack(int x,int &i,int &j){i=x/; j=x%;}
void unpack2(int x,int &i,int &j,int &s){i=x/; j=(x/)%; s=x%;}
bool update(int x,int y,int s,int i,int j,int sta,int w)
{
if(f[x][y][s]>w){f[x][y][s]=w; pre[x][y][s]=pack2(i,j,sta); return ;}
return ;
}
void spfa(int sta)
{
while(q.size())
{
int i,j;
unpack(q.front(),i,j); inq[q.front()]=; q.pop();
for(int k=;k<;k++)
{
int x=i+dx[k],y=j+dy[k],tmp;
if(x==-||y==-||x==n||y==m)continue;//!!!
if(update(x,y,sta,i,j,sta,f[i][j][sta]+a[x][y])&&!inq[tmp=pack(x,y)])//不改变连通性
q.push(tmp),inq[tmp]=;
}
}
}
void dfs(int x,int y,int sta)
{
if(!pre[x][y][sta])return;
vis[x][y]=;
int i,j,s;
unpack2(pre[x][y][sta],i,j,s);
dfs(i,j,s);
if(i==x&&j==y)dfs(i,j,sta-s);//合并转移
}
void print()
{
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("_");
}
printf("\n");
}
}
int main()
{
scanf("%d%d",&n,&m);
memset(f,0x3f,sizeof f);
for(int i=;i<n;i++)
for(int j=;j<m;j++)
{
scanf("%d",&a[i][j]);
if(!a[i][j])f[i][j][<<(K++)]=;
}
mx=(<<K);
for(int sta=;sta<mx;sta++)
{
for(int i=;i<n;i++)
for(int j=,tmp;j<m;j++)//以(i,j)为媒介
{
for(int s=(sta&(sta-));s;s=(s-)&sta)
update(i,j,sta,i,j,s,f[i][j][s]+f[i][j][sta-s]-a[i][j]);//点权重复
if(f[i][j][sta]!=inf)q.push(tmp=pack(i,j)),inq[tmp]=;//inq!
}
spfa(sta);//更新不同位置的sta
}
for(int i=;i<n;i++)
for(int j=;j<m;j++)
if(!a[i][j])
{
printf("%d\n",f[i][j][mx-]);
dfs(i,j,mx-);
print();
return ;
}
}

bzoj2595 [Wc2008]游览计划——斯坦纳树的更多相关文章

  1. bzoj2595: [Wc2008]游览计划 斯坦纳树

    斯坦纳树是在一个图中选取某些特定点使其联通(可以选取额外的点),要求花费最小,最小生成树是斯坦纳树的一种特殊情况 我们用dp[i][j]来表示以i为根,和j状态是否和i联通,那么有 转移方程: dp[ ...

  2. BZOJ2595: [Wc2008]游览计划(斯坦纳树,状压DP)

    Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 2030  Solved: 986[Submit][Status][ ...

  3. 【BZOJ2595】[Wc2008]游览计划 斯坦纳树

    [BZOJ2595][Wc2008]游览计划 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为 ...

  4. Luogu 4294 [WC2008]游览计划 | 斯坦纳树

    题目链接 Luogu 4294 (我做这道题的时候BZOJ全站的SPJ都炸了 提交秒WA 幸好有洛谷) 题解 这道题是[斯坦纳树]的经典例题.斯坦纳树是这样一类问题:带边权无向图上有几个(一般约10个 ...

  5. 【BZOJ-2595】游览计划 斯坦纳树

    2595: [Wc2008]游览计划 Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 1518  Solved: 7 ...

  6. BZOJ 2595 [Wc2008]游览计划 ——斯坦纳树

    [题目分析] 斯坦纳树=子集DP+SPFA? 用来学习斯坦纳树的模板. 大概就是用二进制来表示树包含的点,然后用跟几点表示树的形态. 更新分为两种,一种是合并两个子集,一种是换根,换根用SPFA迭代即 ...

  7. P4294 [WC2008]游览计划 (斯坦纳树)

    题目链接 差不多是斯坦纳树裸题,不过边权化成了点权,这样在合并两棵子树时需要去掉根结点的权值,防止重复. 题目还要求输出解,只要在转移时记录下路径,然后dfs一遍就好了. #include<bi ...

  8. 洛谷4294 [WC2008]游览计划——斯坦纳树

    题目:https://www.luogu.org/problemnew/show/P4294 大概是状压.两种转移,一个是以同一个点为中心,S由自己的子集拼起来:一个是S相同.中心不同的同层转移. 注 ...

  9. BZOJ2595 Wc2008 游览计划 【斯坦纳树】【状压DP】*

    BZOJ2595 Wc2008 游览计划 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个 ...

随机推荐

  1. 关于Python中的classmethod

    Python 中的 classmethod classmethod: 作用是直接将自己的类对象,传给类方法. 一.classmethod 1)不用classmethod的时候 你的代码可能是这样写的, ...

  2. 浏览器的 local storage

    浏览器 local storage      本地存储 session storage    会话存储 cookies                  本地存储 1.     local stora ...

  3. pig常用命令

    一.pig: pig提供了一个基于Hadoop的并行地执行数据流处理的引擎.它包含了一种脚本语言,称为Pig Latin.(类似SQL) 二.Pig Latin: 1.注释: 单行:-- 多行:/* ...

  4. 内核调试-perf introduction

    perf概念 perf_event Perf_events是目前在Linux上使用广泛的profiling/tracing工具,除了本身是内核(kernel)的组成部分以外,还提供了用户空间(user ...

  5. c/c++排坑(4) -- c/c++中返回局部变量

    返回c语言中的局部变量 先看一段代码猜猜,打印值: #include <iostream> using namespace std; char * func(); int main() { ...

  6. HUD 1426 Sudoku Killer (DFS)

    链接 : Here! 思路 : 记录下所有 "?" , 出现的位置, 然后 $DFS$ 一下, 对于每个位置来说都可以填充 $9$ 种数值, 然后对于判断填充是否合法需要三个标记数 ...

  7. 28.function_score自定义相关度分数算法

    我们可以做到自定义一个function_score函数,自己将某个field的值,跟es内置算出来的分数进行运算,然后由自己指定的field来进行分数的增强     一.准备数据 给所有的帖子数据增加 ...

  8. 第五节:numpy之数组维度处理

  9. 腾讯云:ubuntu搭建 FTP 文件服务

    搭建 FTP 文件服务 安装并启动 FTP 服务 任务时间:5min ~ 10min 安装 VSFTPD 使用 apt-get 安装 vsftpd: sudo apt-get install vsft ...

  10. elasticsearch 数据导入(九)

    说明 maven依赖 官方客户端 https://www.elastic.co/guide/en/elasticsearch/client/java-rest/6.4/index.html <d ...