link

题目大意:给定一个网格图,有些点是关键点,选择格点有代价,求把所有关键点联通的最小代价

斯坦纳树模板题

斯坦纳树问题:给定一个图结构,有一些点是关键点,求把这些关键点联通的最小代价e

斯坦纳树问题其实是最小生成树MST问题的扩展

考虑状压DP,设f[x][s]代表当前以x为根的树,关键点选取状态集合为s时的最小代价

考虑s由两个子集s1和s2转移过来,则DP方程为f[x][s]=f[x][s1]+f[x][s2]。如果是点权,去重还要减去val[x]

考虑s由其它点转移过来,那么就枚举其它点,f[x][s]=f[y][s]+val[x][y],发现这其实就是最短路的转移形式,我们一开始把所有f<inf的点扔队列里跑spfa就行了

初始化:对于关键点x,有f[x][只包含x的集合]=0,其它为inf

最后输出的答案即为f[某个关键点][(1<<tot)-1]

瞎写的板子:

  1. for (int s = 1; s < (1 << tot); s++)
  2. {
  3. for (int i = 1; i <= n; i++)
  4. {
  5. for (s1 + s2 == s)
  6. {
  7. chkmin(f[i][s], f[i][s1]+f[i][s2]);
  8. if (f[i][s] < inf) q.push(i), vis[i] = true;
  9. }
  10. }
  11. while (!q.empty())
  12. {
  13. int x = q.front(); q.pop(), vis[x] = false;
  14. for (int i : out[x]) if (f[x][s] + dis[x][i] < f[i][s])
  15. {
  16. f[i][s] = f[x][s] + dis[x][i];
  17. if (vis[i] == false) vis[i] = true, q.push(i);
  18. }
  19. }
  20. }

本题题解:

直接套用板子即可。

由于还要输出方案,我们维护一个pre,记录这个状态从哪个状态转移过来的,dfs一遍就行了。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <queue>
  4. using namespace std;
  5. const int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
  6. struct data { int x, y, s; } pre[15][15][1050];
  7. int n, m, tot, mp[15][15], f[15][15][1050], ex, ey;
  8. bool vis[15][15], ans[15][15];
  9. void dfs(int x, int y, int s)
  10. {
  11. if (pre[x][y][s].s == 0) return;
  12. ans[x][y] = true;
  13. dfs(pre[x][y][s].x, pre[x][y][s].y, pre[x][y][s].s);
  14. if (pre[x][y][s].x == x && pre[x][y][s].y == y) dfs(pre[x][y][s].x, pre[x][y][s].y, pre[x][y][s].s ^ s);
  15. }
  16. int main()
  17. {
  18. scanf("%d%d", &n, &m); memset(f, 0x3f, sizeof(f));
  19. for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++)
  20. {
  21. scanf("%d", &mp[i][j]);
  22. if (mp[i][j] == 0) f[i][j][1 << (tot++)] = 0, ex = i, ey = j;
  23. }
  24. for (int s = 1; s < (1 << tot); s++)
  25. {
  26. queue<int> qx, qy;
  27. for (int i = 1; i <= n; i++)
  28. {
  29. for (int j = 1; j <= m; j++)
  30. {
  31. for (int s1 = s; s1 > 0; s1 = (s1 - 1) & s)
  32. {
  33. int s2 = s1 ^ s;
  34. if (f[i][j][s] > f[i][j][s1] + f[i][j][s2] - mp[i][j])
  35. {
  36. f[i][j][s] = f[i][j][s1] + f[i][j][s2] - mp[i][j];
  37. pre[i][j][s] = (data){i, j, s1};
  38. }
  39. }
  40. if (vis[i][j] == false && f[i][j][s] != 0x3f3f3f3f) qx.push(i), qy.push(j), vis[i][j] = true;
  41. }
  42. }
  43. while (!qx.empty())
  44. {
  45. int x = qx.front(), y = qy.front(); qx.pop(), qy.pop(); vis[x][y] = false;
  46. for (int d = 0; d < 4; d++)
  47. {
  48. int nx = x + dx[d], ny = y + dy[d];
  49. if (nx >= 1 && nx <= n && ny >= 1 && ny <= m)
  50. {
  51. if (f[nx][ny][s] > f[x][y][s] + mp[nx][ny])
  52. {
  53. f[nx][ny][s] = f[x][y][s] + mp[nx][ny];
  54. pre[nx][ny][s] = (data){x, y, s};
  55. if (vis[nx][ny] == false) vis[nx][ny] = true, qx.push(nx), qy.push(ny);
  56. }
  57. }
  58. }
  59. }
  60. }
  61. printf("%d\n", f[ex][ey][(1 << tot) - 1]);
  62. dfs(ex, ey, (1 << tot) - 1);
  63. for (int i = 1; i <= n; i++)
  64. {
  65. for (int j = 1; j <= m; j++)
  66. if (mp[i][j] == 0) printf("x");
  67. else if (ans[i][j]) printf("o");
  68. else printf("_");
  69. printf("\n");
  70. }
  71. return 0;
  72. }

luogu4294 [WC2008]游览计划(状压DP/斯坦纳树)的更多相关文章

  1. [WC2008]游览计划 状压DP,斯坦纳树

    ---题面--- 题解: 这是一道斯坦纳树的题,用状压+spfa来解决 什么是斯坦纳树? 一开始还以为是数据结构来着,其实跟最小生成树很像,大致就是最小生成树只能在各个点之间直接相连,而斯坦纳树则允许 ...

  2. [WC2008]游览计划(状压dp)

    题面太鬼畜不粘了. 题意就是给一张n*m的网格图,每个点有点权,有k个关键点,让你把这k个关键点连成一个联通快的最小代价. 题解 这题nmk都非常小,解法肯定是状压,比较一般的解法插头dp,但不太好写 ...

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

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

  4. [BZOJ4006][JLOI2015]管道连接 状压dp+斯坦纳树

    4006: [JLOI2015]管道连接 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1020  Solved: 552[Submit][Statu ...

  5. 动态规划:状压DP-斯坦纳树

    最小生成树是最小斯坦纳树的一种特殊情况 最小生成树是在给定的点集和边中寻求最短网络使所有点连通 而最小斯坦纳树允许在给定点外增加额外的点,使生成的最短网络开销最小 BZOJ2595 题意是给定一个棋盘 ...

  6. BZOJ.2595.[WC2008]游览计划(DP 斯坦纳树)

    题目链接 f[i][s]表示以i为根节点,当前关键点的连通状态为s(每个点是否已与i连通)时的最优解.i是枚举得到的根节点,有了根节点就容易DP了. 那么i为根节点时,其状态s的更新为 \(f[i][ ...

  7. 【状压dp】Trie 树 @中山纪念中学20170304

    目录 Trie 树 PROBLEM 题目描述 输入 输出 样例输入 样例输出 SOLUTION CODE Trie 树 PROBLEM 题目描述 字母(Trie)树是一个表示一个字符串集合中所有字符串 ...

  8. HDU.3311.Dig The Wells(DP 斯坦纳树)

    题目链接 \(Description\) 有n座庙.一共n+m个点,可以在任意一些点修建水井,不同位置花费不同:也可以某些点之间连无向边共享水.求使n座庙都有水的最小花费. \(Solution\) ...

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

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

随机推荐

  1. ubuntu Qt5 opencv3.4 项目配置

    #------------------------------------------------- # # Project created by QtCreator 2019-03-25T14:14 ...

  2. C#在控制台输出异常所在的行数

    对于异常,我们经常用try-catch语句来处理,一种常见的方式是在catch语句块用MessageBox.Show("异常")这种弹窗的方式来报告异常.但是有些时候,有些异常发生 ...

  3. Python一行代码搞定的事情

    python -m SimpleHTTPServer 8000 http://127.0.0.1:8000/ 有了这一行代码分享本地盘内容就不需要FTP了. pydoc:Python文档工具 pyth ...

  4. [Token] 从index.jsp中获取Token

    import com.eviware.soapui.support.GroovyUtils def groovyUtils = new GroovyUtils( context ) def holde ...

  5. oracle 环境变量(中文显示乱码)

     NLS_LANGSIMPLIFIED CHINESE_CHINA.ZHS16GBK 

  6. Word2013写CSDN博客

    目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...

  7. Quartus中代码字体大小的调整方法

    Quartus中代码大小的调整方法 网友 "一纸玫瑰"整理 第一步:点击Tools(工具) 第二步:点击Options(选项) 第三步:Text Editor(文本编辑)/Font ...

  8. 【微服务架构】SpringCloud之Feign(五)

    Feign简介 Feign 是一个声明web服务客户端,这便得编写web服务客户端更容易,使用Feign 创建一个接口并对它进行注解,它具有可插拔的注解支持包括Feign注解与JAX-RS注解,Fei ...

  9. Java的StringTokenizer类

    StringTokenizer是java中object类的一个子类,继承自 Enumeration接口.此类允许一个应用程序进入一个令牌(tokens),而且StringTokenizer类用起来比S ...

  10. jmeter-性能监控(InfluxDB+Grafana)

    测试结果实时监控:jmeter+influxdb+grafana InfluxDB:存储实时数据的DB Grafana:DB中存储的实时数据可以在浏览器查看 --------------------- ...