上个月写的题qwq……突然想写篇博客

题目:

洛谷4294

分析:

斯坦纳树模板题。

简单来说,斯坦纳树问题就是给定一张有边权(或点权)的无向图,要求选若干条边使图中一些选定的点连通(可以经过其他点),且边权(或点权)之和最小。很明显,这样最终形成的是一棵树。

通常,斯坦纳树问题规模都比较小。考虑状压DP。用\(dp[u][S]\)表示让点\(u\)与集合\(S\)中所有关键点连通的最小花费。有如下两种转移:

第一,把两条到\(u\)的路径拼在一起,减去重合点\(u\)的点权,即(\(w_u\)表示点\(u\)的点权,\(S'\)表示\(S\)的一个真非空子集,\(S-S'\)表示以\(S'\)相对于\(S\)的补集,下同):

\[dp[u][S]=min(dp[u][S']+dp[u][S-S']-w_u)
\]

第二,延伸一条路径,即(\(v\)与\(u\)之间存在一条边):

\[dp[u][S]=min(dp[v][S]+w_u)
\]

第二种存在循环更新的问题。但是它长得很像最短路,于是大力跑最短路算法即可。

注意更新顺序,要从小到大枚举集合\(S\),先更新第一种再更新第二种。

代码:

把上面的点\(u\)换成坐标就好了……

dp的时候记一下从哪个状态转移来的。

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <cctype>
  5. #include <queue>
  6. #include <functional>
  7. using namespace std;
  8. #define _ 0
  9. namespace zyt
  10. {
  11. template<typename T>
  12. inline void read(T &x)
  13. {
  14. char c;
  15. bool f = false;
  16. x = 0;
  17. do
  18. c = getchar();
  19. while (c != '-' && !isdigit(c));
  20. if (c == '-')
  21. f = true, c = getchar();
  22. do
  23. x = x * 10 + c - '0', c = getchar();
  24. while (isdigit(c));
  25. if (f)
  26. x = -x;
  27. }
  28. template<typename T>
  29. inline void write(T x)
  30. {
  31. static char buf[20];
  32. char *pos = buf;
  33. if (x < 0)
  34. putchar('-'), x = -x;
  35. do
  36. *pos++ = x % 10 + '0';
  37. while (x /= 10);
  38. while (pos > buf)
  39. putchar(*--pos);
  40. }
  41. const int N = 10, ST = 1 << N, INF = 0x3f3f3f3f;
  42. struct _pre
  43. {
  44. int x, y, st;
  45. _pre(const int _x = -1, const int _y = -1, const int _st = -1)
  46. : x(_x), y(_y), st(_st) {}
  47. }pre[N][N][ST];
  48. struct point
  49. {
  50. int x, y;
  51. point(const int _x = 0, const int _y = 0)
  52. : x(_x), y(_y) {}
  53. bool operator < (const point &b) const
  54. {
  55. return x == b.x ? y < b.y : x < b.x;
  56. }
  57. };
  58. int f[N][N][ST], arr[N][N], n, m, k;
  59. const int dx[] = {0, 0, 1, -1};
  60. const int dy[] = {1, -1, 0, 0};
  61. void Dijkstra(const int s)
  62. {
  63. typedef pair<int, point> pip;
  64. static priority_queue<pip, vector<pip>, greater<pip> > q;
  65. static bool vis[N][N];
  66. while (!q.empty())
  67. q.pop();
  68. for (int i = 0; i < n; i++)
  69. for (int j = 0; j < m; j++)
  70. {
  71. q.push(make_pair(f[i][j][s], point(i, j)));
  72. vis[i][j] = false;
  73. }
  74. while (!q.empty())
  75. {
  76. point u = q.top().second;
  77. q.pop();
  78. vis[u.x][u.y] = true;
  79. for (int i = 0; i < 4; i++)
  80. {
  81. point v = point(u.x + dx[i], u.y + dy[i]);
  82. if (v.x < 0 || v.x >= n || v.y < 0 || v.y >= m || vis[v.x][v.y])
  83. continue;
  84. if (f[v.x][v.y][s] > f[u.x][u.y][s] + arr[v.x][v.y])
  85. {
  86. f[v.x][v.y][s] = f[u.x][u.y][s] + arr[v.x][v.y];
  87. pre[v.x][v.y][s] = _pre(u.x, u.y, s);
  88. q.push(make_pair(f[v.x][v.y][s], v));
  89. }
  90. }
  91. }
  92. }
  93. bool mark[N][N];
  94. void dfs(const _pre p)
  95. {
  96. mark[p.x][p.y] = true;
  97. _pre nxt = pre[p.x][p.y][p.st];
  98. if (nxt.x == -1 && nxt.y == -1 && nxt.st == -1)
  99. return;
  100. dfs(nxt);
  101. if (nxt.st != p.st)
  102. {
  103. nxt.st ^= p.st;
  104. dfs(nxt);
  105. }
  106. }
  107. int work()
  108. {
  109. read(n), read(m);
  110. for (int i = 0; i < n; i++)
  111. {
  112. memset(f[i], INF, sizeof(int[m][ST]));
  113. for (int j = 0; j < m; j++)
  114. {
  115. read(arr[i][j]);
  116. if (!arr[i][j])
  117. f[i][j][1 << (k++)] = 0;
  118. }
  119. }
  120. for (int i = 0; i < (1 << k); i++)
  121. {
  122. for (int j = (i - 1) & i; j; j = (j - 1) & i)
  123. for (int x = 0; x < n; x++)
  124. for (int y = 0; y < m; y++)
  125. if (f[x][y][i] > f[x][y][j] + f[x][y][i ^ j] - arr[x][y])
  126. {
  127. f[x][y][i] = f[x][y][j] + f[x][y][i ^ j] - arr[x][y];
  128. pre[x][y][i] = _pre(x, y, j);
  129. }
  130. Dijkstra(i);
  131. }
  132. int ans = INF;
  133. _pre pans;
  134. for (int i = 0; i < n; i++)
  135. for (int j = 0; j < m; j++)
  136. if (ans > f[i][j][(1 << k) - 1])
  137. {
  138. ans = f[i][j][(1 << k) - 1];
  139. pans = _pre(i, j, (1 << k) - 1);
  140. }
  141. write(ans), putchar('\n');
  142. dfs(pans);
  143. for (int i = 0; i < n; i++)
  144. {
  145. for (int j = 0; j < m; j++)
  146. if (!arr[i][j])
  147. putchar('x');
  148. else if (mark[i][j])
  149. putchar('o');
  150. else
  151. putchar('_');
  152. putchar('\n');
  153. }
  154. return (0^_^0);
  155. }
  156. }
  157. int main()
  158. {
  159. return zyt::work();
  160. }

【BZOJ2595_洛谷4294】[WC2008]游览计划(斯坦纳树_状压DP)的更多相关文章

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

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

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

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

  3. [bzoj4006][JLOI2015]管道连接_斯坦纳树_状压dp

    管道连接 bzoj-4006 JLOI-2015 题目大意:给定一张$n$个节点$m$条边的带边权无向图.并且给定$p$个重要节点,每个重要节点都有一个颜色.求一个边权和最小的边集使得颜色相同的重要节 ...

  4. BZOJ 4006 Luogu P3264 [JLOI2015]管道连接 (斯坦纳树、状压DP)

    题目链接: (bzoj)https://www.lydsy.com/JudgeOnline/problem.php?id=4006 (luogu)https://www.luogu.org/probl ...

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

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

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

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

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

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

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

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

  9. bzoj2595 [Wc2008]游览计划——斯坦纳树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2595 今天刚学了斯坦纳树,还不太会,写一道题练习一下: 参考了博客:http://www.c ...

随机推荐

  1. 原生js实现三个按钮绑定三个计时器,点击其中一个按钮,开启当前计时器,另外另个不开启

    今天在某个前端交流群,有个小伙伴问了一个小功能,自己想了一下,代码如下,可以实现基本功能: 下面是html结构 <div id="demo"> <input ty ...

  2. uva 1444 Knowledge for the masses

    uva 1444 Description   You are in a library equipped with bookracks that move on rails. There are ma ...

  3. git命令大杂烩

    查看版本库中的文件: git ls-files添加到暂存区: git add filesName|\folderName(循环递归) git add .(添加当前目录下的所有文件包括子目录,如果添加文 ...

  4. [luoguP1026] 统计单词个数(DP)

    传送门 题解 #include <cstdio> #include <cstring> #define max(x, y) ((x) > (y) ? (x) : (y)) ...

  5. 仪仗队(codevs 2296)

    题目描述 Description 作为体育委员,C君负责这次运动会仪仗队的训练.仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来 ...

  6. jquery simple modal

    窗体API定义丰富,而且使用也很容易上手.官方地址:http://www.ericmmartin.com/projects/simplemodal/从官方下载插件,在文件中引用<script t ...

  7. STM8S PWM 应用 呼吸灯

    //主功能接受:使用MCU STM8S105C6 的PWM通道2 PC2 来做呼吸灯 已经验证OK,呵 //呵,这个PWM设置刚開始用还是有点麻烦,由于是自己摸索.花点时间.还是解决了 . //所用子 ...

  8. Hadoop的学习前奏(二)——Hadoop集群的配置

    前言: Hadoop集群的配置即全然分布式Hadoop配置. 笔者的环境: Linux:  CentOS 6.6(Final) x64   JDK:    java version "1.7 ...

  9. IOS - UIView停止交互

    UIView停止交互(失去焦点): 设置userInteractionEnabled=NO, 获取交互设置YES. 能够应用于UIButton, UITextField等交互型控件. [editBut ...

  10. LNMP环境搭建——PHP篇

    一.源代码安装 1.编译安装 ./configure --prefix=/usr/local/php\ --with-config-file-path=/usr/local/php/etc --wit ...