bzoj2595

一开始看是插头dp,后来发现还有一个叫斯坦纳树的东西

什么叫斯坦纳树,就是使给定点连通开销和最小的树(可以包含多余的点)

到这张平面图上,我们不难想到用dp来解决,设f[x,y,S]表示连通集合为S,树根为点(x,y)的最小开销

不难得到两个方程式

f[x,y,S]=min(f[x,y,s‘]+f[x,y,S-s‘]-a[x,y]) S‘是S的一个子集,相当于合并两个数

f[x,y,S]=min(f[x‘,y‘,S]+a[x,y]) (x‘,y‘)与(x,y)相邻

由于景点很少,我们显然可以用状压dp,初始f[景点坐标,景点状态]=0

第一个方程转移大家都会,第二个方程转移是没有明确转移顺序,只要转移起点,因此我们用spfa转移

所以总的处理转移,我们穷举连通状况,然后先用第一个方程转移,然后再用第二个方程转移

  1 const dx:array[1..4] of longint=(0,0,1,-1);
  2       dy:array[1..4] of longint=(1,-1,0,0);
  3       inf=1000000007;
  4 type node=record
  5        x,y,k:longint;
  6      end;
  7
  8 var q:array[0..1000010] of node;
  9     pre:array[0..11,0..11,0..1025] of node;
 10     f:array[0..11,0..11,0..1025] of longint;
 11     v:array[0..11,0..11] of boolean;
 12     a:array[0..11,0..11] of longint;
 13     t,h,r,k,i,j,s,n,m,x,y:longint;
 14
 15 function make(i,j,k:longint):node;
 16   begin
 17     make.x:=i;
 18     make.y:=j;
 19     make.k:=k;
 20   end;
 21
 22 procedure spfa(k:longint);
 23   var i,x,y,x0,y0:longint;
 24   begin
 25     while h<=r do
 26     begin
 27       x0:=q[h].x; y0:=q[h].y;
 28       v[x0,y0]:=false;
 29       for i:=1 to 4 do
 30       begin
 31         x:=x0+dx[i];
 32         y:=y0+dy[i];
 33          if (x<0) or (x>n) or (y<0) or (y>m) then continue;
 34         if f[x,y,k]>f[x0,y0,k]+a[x,y] then
 35         begin
 36           f[x,y,k]:=f[x0,y0,k]+a[x,y];
 37           pre[x,y,k]:=make(x0,y0,k);
 38           if not v[x,y] then
 39           begin
 40             v[x,y]:=true;
 41             inc(r);
 42             q[r].x:=x; q[r].y:=y;
 43           end;
 44         end;
 45       end;
 46       inc(h);
 47     end;
 48   end;
 49
 50 procedure dfs(x,y,k:longint);
 51   var m:node;
 52   begin
 53     v[x,y]:=true;
 54     m:=pre[x,y,k];
 55     if m.x=0 then exit;
 56     dfs(m.x,m.y,m.k);
 57     if (m.x=x) and (m.y=y) then dfs(m.x,m.y,k-m.k);
 58   end;
 59
 60 begin
 61   readln(n,m);
 62   for i:=1 to n do
 63     for j:=1 to m do
 64       for k:=0 to 1024 do
 65         f[i,j,k]:=inf;
 66   for i:=1 to n do
 67     for j:=1 to m do
 68     begin
 69       read(a[i,j]);
 70       if a[i,j]=0 then
 71       begin
 72         f[i,j,1 shl t]:=0;
 73         inc(t);
 74       end;
 75     end;
 76   h:=1;
 77   r:=0;
 78   for k:=1 to 1 shl t-1 do
 79   begin
 80     for i:=1 to n do
 81       for j:=1 to m do
 82       begin
 83         s:=k and (k-1);
 84         while s<>0 do  //穷举子集
 85         begin
 86           if f[i,j,k]>f[i,j,s]+f[i,j,k-s]-a[i,j] then
 87           begin
 88             f[i,j,k]:=f[i,j,s]+f[i,j,k-s]-a[i,j];
 89             pre[i,j,k]:=make(i,j,s); //记录从哪转移来的
 90           end;
 91           s:=k and (s-1);
 92         end;
 93         if f[i,j,k]<inf then
 94         begin
 95           v[i,j]:=true;
 96           inc(r);
 97           q[r].x:=i; q[r].y:=j;
 98         end;
 99       end;
100     spfa(k);
101     h:=1;
102     r:=0;
103   end;
104   for i:=1 to n do
105     for j:=1 to m do
106       if a[i,j]=0 then
107       begin
108         x:=i;
109         y:=j;
110         break;
111       end;
112
113   writeln(f[x,y,1 shl t-1]);
114   dfs(x,y,1 shl t-1);
115   for i:=1 to n do
116   begin
117     for j:=1 to m do
118       if a[i,j]=0 then write(‘x‘)
119       else if v[i,j] then write(‘o‘)
120       else write(‘_‘);
121     writeln;
122   end;
123 end.

时间: 2024-10-03 02:38:05

bzoj2595的相关文章

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

[BZOJ2595][Wc2008]游览计划 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点:否则表示控制该方块至少需要的志愿者数目. 相邻的整数用 (若干个) 空格隔开,行首行末也可能有多余的空格. Output 由 N + 1行组成.第一行为一个整数,表示你所给出的方案中安排的志愿者总数目. 接下来 N行,每行M 个字符,描述方案中相应方块的情况: z  ‘_’(下划线)表示该

bzoj2595 [Wc2008]游览计划

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2595 [题解] 斯坦纳树模板题.学了一发斯坦纳树. 对于一般的斯坦纳树,是 给出一些点和一些关键点和边,要求选择权值和最小的连通块使得关键点连通. 那么一般我们用f(x,status)表示在x,状态为status的最小权值和. 本题我们采用f(i,j,status)表示在(i,j),状态为status的最小权值和. 一开始权值就是题目给的,如果是景点那么在对应的标号的status赋值即可.

【BZOJ2595】【Wc2008】游览计划、斯坦纳树

题解:斯坦纳树,实现神马的在代码里面有还看得过去的注释. 代码: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 15 #define inf 0x3f3f3f3f using namespace std; const int dx[]={0,0,1,-1}; const int dy[

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

Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 2030  Solved: 986[Submit][Status][Discuss] Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点:否则表示控制该方块至少需要的志愿者数目. 相邻的整数用 (若干个) 空格隔开,行首行末也可能有多余的空格. Outpu

[入门向选讲] 插头DP:从零概念到入门 (例题:HDU1693 COGS1283 BZOJ2310 BZOJ2331)

转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7326874.html 最近搞了一下插头DP的基础知识……这真的是一种很锻炼人的题型…… 每一道题的状态都不一样,并且有不少的分类讨论,让插头DP十分锻炼思维的全面性和严谨性. 下面我们一起来学习插头DP的内容吧! 插头DP主要用来处理一系列基于连通性状态压缩的动态规划问题,处理的具体问题有很多种,并且一般数据规模较小. 由于棋盘有很特殊的结构,使得它可以与“连通性”有很强的联系,因此插头DP最常见的应用要数

【待填坑】bzoj上WC的题解

之前在bzoj上做了几道WC的题目,现在整理一下 bzoj2115 去膜拜莫队的<高斯消元解xor方程组> bzoj2597 LCT维护MST bzoj1758 分数规划+树分治+单调队列 bzoj2595 斯坦纳树,一类用spfa转移的dp,具体可以膜拜<spfa算法的优化及应用>(我是不会插头的蒟蒻) bzoj2597 补集思想之后就变成了显然的平方流 bzoj3052 树上带修改莫队算法(如果一无所知的话,可以按2038 1086 3757 3052的顺序做) bzoj145

BZOJ 2595: [Wc2008]游览计划 [DP 状压 斯坦纳树 spfa]【学习笔记】

传送门 题意:略 论文 <SPFA算法的优化及应用> http://www.cnblogs.com/lazycal/p/bzoj-2595.html 本题的核心就是求斯坦纳树: Steiner Tree: Given an undirected graph with non-negative edge weights and a subset of vertices, usually referred to as terminals, the Steiner tree problem in g

bzoj3205

和bzoj2595类似,也是斯坦纳树 设f[l,r,]表示在点i机器人组合成了l-r最少推的次数,然后可得 f[l,r,i]=min(f[l,m,i]+f[m+1,r,i]) f[l,r,i]=min(f[l,r,j]+1) 点j能推到i 但是这样做肯定会TLE,考虑两个优化 首先,一开始其实有很多根本用不到,我们可以先从机器人初始位置搜下去,找到所有可以访问的点做dp即可 其次,观察第二个方程,它的边权都是1,我们一定要用spfa转移吗?不,我们可以用直接宽搜 具体的我们维护两个队列,第一个队

bzoj刷题(shui)记录

放假刷了一个月的水题,集中写一下题解吧. bzoj1858:线段树随便维护一下. code bzoj2705:莫比乌斯反演裸题. code bzoj1202:并查集,但是我写了一种跟floyd很像的奇怪的东西. code bzoj1072:暴力. bzoj2431:dp f[i][j]=sum(f[i-1],[k]) code bzoj3505:组合数学. code bzoj1058:两棵平衡树. code bzoj1922:维护两个距离,然后更新答案. code bzoj1009:之前写过题解