写的第一道斯坦纳树的题目。斯坦纳树在信息学中的应用一般为:在\(n\)个点之间给定\(k\)条边并相应的边权,求在保证给定\(m\)个点联通的条件下的最小边权和。解决此类问题的方法即为SPFA + 状压DP。参考论文:姜碧野 《SPFA的优化与应用》

  我们用\(dp[u][S]\)表示以u为根,联通状态为S(01状态)的最小权值。以u为根:最优解必然构成一棵最小生成树。那么有两种转移方式:

  \(dp[u][S] = dp[u][k'] + dp[u][k''] - a[u] \left ( S = k' + k'' \right )\)

  这一个可以理解为\(u\)点为树上的一个分叉点,由该点分别走向两侧,一侧联通\(k'\)集合,一侧联通\(k''\)集合,通过\(u\)点联通成\(S\)集合。这种转移比较好处理,只需枚举子集即可。

  \(dp[u][S] = dp[v][S] + w[u][v]\)

  这里是从\(u\)点走向了\(v\)点,联通了这两个集合,通过\(u -> v\)这条边来连接。这一种情况就比较复杂了:\(u\)可以转移到\(v\),\(v\)也可以转移到\(u\),但这个方程式却给了我们一点联想:好像很像是最短路中的松弛操作呀。其满足三角形不等式,虽然图中有环的存在,但最优解并不构成环。所以我们用SPFA来进行这一部分的DP。

  在本题中,\(f[i][j][S]\)代表以点\(i, j\)为根,联通状态为\(S\)的最优权值。

#include <bits/stdc++.h>
using namespace std;
#define maxn 12
#define maxm (1 << 10) + 2
#define INF 1e9
int n, m, K, f[maxn][maxn][maxm];
int a[maxn][maxn], bin[maxn];
int dx[] = {, , , -}, dy[] = {, -, , };
bool vis[maxn][maxn]; struct node
{
int x, y;
node (int _x = , int _y = ) { x = _x, y = _y; }
};
queue <node> q; struct Path
{
int x, y, s;
Path (int _x = , int _y = , int _s = ) { x = _x, y = _y, s = _s; }
}path[maxn][maxn][maxm]; int read()
{
int x = , k = ;
char c;
c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} void init()
{
bin[] = ;
for(int i = ; i < ; i ++) bin[i] = bin[i - ] << ;
} void SPFA(int S)
{
while(!q.empty())
{
int x = q.front().x, y = q.front().y;
vis[x][y] = , q.pop();
for(int k = ; k < ; k ++)
{
int X = x + dx[k], Y = y + dy[k];
if(X < || Y < || X > n || Y > m) continue;
if(f[X][Y][S] > f[x][y][S] + a[X][Y])
{
f[X][Y][S] = f[x][y][S] + a[X][Y];
path[X][Y][S] = Path(x, y, S);
if(!vis[X][Y]) q.push(node(X, Y)), vis[X][Y] = ;
}
}
}
} #define t path[x][y][S]
void dfs(int x, int y, int S)
{
if(x > INF || !t.s) return;
vis[x][y] = ; dfs(t.x, t.y, t.s);
if(t.x == x || t.y == y) dfs(x, y, S ^ t.s);
}
#undef t void Solve()
{
for(int S = ; S < bin[K]; SPFA(S ++))
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++)
{
for(int k = S & (S - ); k; k = (k - ) & S)
{
int t = f[i][j][k] + f[i][j][S ^ k] - a[i][j];
if(t < f[i][j][S]) { f[i][j][S] = t; path[i][j][S] = Path(i, j, k); }
}
if(f[i][j][S] != INF) { q.push(node(i, j)); vis[i][j] = ; }
}
} void Get_ans()
{
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++)
if(!a[i][j])
{
dfs(i, j, bin[K] - );
printf("%d\n", f[i][j][bin[K] - ]);
return;
}
} int main()
{
init();
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 ++;
}
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++)
for(int k = ; k < bin[K]; k ++)
f[i][j][k] = path[i][j][k].x = INF;
K = ;
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++)
if(!a[i][j]) f[i][j][bin[K]] = , K ++;
Solve();
memset(vis, , sizeof(vis));
Get_ans();
for(int i = ; i <= n; i ++, putchar('\n'))
for(int j = ; j <= m; j ++)
if(!a[i][j]) putchar('x');
else if(vis[i][j]) putchar('o');
else putchar('_');
return ;
}

【题解】WC2008游览计划的更多相关文章

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

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

  2. 【LG4294】[WC2008]游览计划

    [LG4294][WC2008]游览计划 题面 洛谷 bzoj 题解 斯坦纳树板子题. 斯坦纳树的总结先留个坑. 代码 #include <iostream> #include <c ...

  3. BZOJ_2595_[Wc2008]游览计划_斯坦纳树

    BZOJ_2595_[Wc2008]游览计划_斯坦纳树 题意: 分析: 斯坦纳树裸题,有几个需要注意的地方 给出矩阵,不用自己建图,但枚举子集转移时会算两遍,需要减去当前点的权值 方案记录比较麻烦,两 ...

  4. [WC2008]游览计划 解题报告

    [WC2008]游览计划 斯坦纳树板子题,其实就是状压dp 令\(dp_{i,s}\)表示任意点\(i\)联通关键点集合\(s\)的最小代价 然后有转移 \[ dp_{i,S}=\min_{T\in ...

  5. bzoj2595 / P4294 [WC2008]游览计划

    P4294 [WC2008]游览计划 斯坦纳树 斯坦纳树,是一种神奇的树.它支持在一个连通图上求包含若干个选定点的最小生成树. 前置算法:spfa+状压dp+dfs(大雾) 我们设$f[o][P]$为 ...

  6. 【BZOJ2595】 [Wc2008]游览计划

    BZOJ2595 [Wc2008]游览计划 Solution 考虑这是一个最小费用连通性的问题,既然大家都说这是什么斯坦纳树那就是的吧... 所以我们肯定可以这样设一个dp状态: \(dp_{i,j, ...

  7. 【BZOJ 2595】2595: [Wc2008]游览计划 (状压DP+spfa,斯坦纳树?)

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

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

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

  9. [bzoj2595][WC2008]游览计划/[bzoj5180][Baltic2016]Cities_斯坦纳树

    游览计划 bzoj-2595 wc-2008 题目大意:题目链接.题目连接. 注释:略. 想法:裸题求斯坦纳树. 斯坦纳树有两种转移方式,设$f[s][i]$表示联通状态为$s$,以$i$为根的最小代 ...

  10. luogu P4294 [WC2008]游览计划

    LINK:游览计划 斯坦纳树例题. 斯坦纳树是这样一类问题:带权无向图上有K个关键点 求出包含这K个点的最小生成树. 也就是说 求最小生成树 但是 并不是整张图 仅限于K个点. 可以发现我们利用克鲁斯 ...

随机推荐

  1. Struts2的动态方法,及result跳转方式,全局结果以及默认的action的配置

    Action动态方法的调用 首先我们需要在struts.xml中去配置一个常量值如下 那么去哪找呢?找到Struts-core.jar并打开 method属性 <action name=&quo ...

  2. 【HCNE题型自我考究】

      H3CNE题目归结 制定标准 组织: 802.1X协议起源于标准的无线局域网协议802.11.主要目的是为了解决有线局域网用户的接入认证问题. 426.一个包含有华为等多厂商设备的交换网络,其VL ...

  3. wampserver 服务器报500错误,侦察小结

    Internal Server Error The server encountered an internal error or misconfiguration and was unable to ...

  4. Python爬虫基础(一)——HTTP

    前言 因特网联系的是世界各地的计算机(通过电缆),万维网联系的是网上的各种各样资源(通过超文本链接),如静态的HTML文件,动态的软件程序······.由于万维网的存在,处于因特网中的每台计算机可以很 ...

  5. 网站apache环境S2-057漏洞 利用POC 远程执行命令漏洞复现

    S2-057漏洞,于2018年8月22日被曝出,该Struts2 057漏洞存在远程执行系统的命令,尤其使用linux系统,apache环境,影响范围较大,危害性较高,如果被攻击者利用直接提权到服务器 ...

  6. C++远征之封装篇(下)-学习笔记

    C++远征之封装篇(下) c++封装概述 下半篇依然围绕类 & 对象进行展开 将原本学过的简单元素融合成复杂的新知识点. 对象 + 数据成员 = 对象成员(对象作为数据成员) 对象 + 数组 ...

  7. node获取URL数据

    req.method  -->GET req.hostname  -->127.0.0.1 req.originalUrl  -->/test/test/test?name=wang ...

  8. react-router 4.0中跳转失灵

    在https://github.com/ReactTraining/history文档中,跳转是 用这种方法,但是,用了之后就存在这么一个问题,网址换了但是页面并没有刷新. 查了资料后,history ...

  9. SGU刷题之路,开始了

    0. 关于SGU的简介 SGU的网址是:acm.sgu.ru 向不了解的同学介绍一下SGU这个题库: 1. 题目难度很高,题目大多很经典. 2. 其数据范围很小,时间和空间要求也都很小,同时很精确.甚 ...

  10. Android应用AsyncTask处理机制详解及源码分析

    1 背景 Android异步处理机制一直都是Android的一个核心,也是应用工程师面试的一个知识点.前面我们分析了Handler异步机制原理(不了解的可以阅读我的<Android异步消息处理机 ...