Codeforces 1749E Cactus Wall 题解 [ 紫 ] [ 01 BFS ] [ 图论建模 ] [ 构造 ] [ adhoc ]
一道很好的思维题,被教练碾压了。
观察
首先从题目给的样例入手:
5 5
.....
.....
.....
.....
.....
这种情况最终的答案是:
YES
....#
...#.
..#..
.#...
#....
所以我们大胆猜测,构造这样的仙人掌防线,需要我们斜着且不间断地排布仙人掌。
这一点其实也可以从题目中 “仙人掌不能四联通放” “需要以四联通的形式堵住怪物” 观察出来,只是初看比较难想到。
因此,我们只要在图中构造一个斜向走的仙人掌防线即可。
假做法
既然我们要用最少的仙人掌去构造这样的一个放置方案,就需要利用到之前已经摆放过的仙人掌了。
同时看到我们求的是一个放置的轮廓线,并且是从左往右放的,那么我们就可以想到经典的按轮廓线转移的线性 dp 。
当这个位置是仙人掌时,我们不需要将这个位置再放上仙人掌,因此直接转移前面的:
\]
当这个位置是空的时,我们要在这里放上仙人掌,因此转移时要加一:
\]
当这个位置是与某个仙人掌四联通时,无法放置,因此不转移。
但是,这个做法实际上是假的,因为我们并不能保证仙人掌防线一定是一直从左往右的,例如:
.......#
......#.
.....#..
....#...
...#....
..#.....
.#......
..#.....
...#....
....#...
...#....
..#.....
.#......
#.......
可以从左上,左下,右上,右下四个地方转移,这就直接说明了本题不满足无后效性,不能用 dp 。因此需要换一种思路。
正解
根据上述分析我们知道,转移可以从左上,左下,右上,右下四个地方来。因此我们可以建出一个图,表示这个点能从其他什么点走过来,形成防线。
这样,就把 dp 变成了 无需满足无后效性的 图论问题。
这是经典的把有后效性的 dp 转化为最短路的 trick 。
复杂度更劣做法
我们把和仙人掌四联通的点设为不可以走的点,对于一个有向边 \(<u,v>\) ,如果 \(v\) 是已有仙人掌的点,那么把这条边的权设为 \(0\) ,否则设为 \(1\) ,这代表着走这里需不需要种仙人掌。
这里由于是无向图,所以要建两倍有向边。
接下来跑一遍 dijkstra 即可,求出的最短路径记录一下自己的先驱,然后顺着最短路径把这上面的点修改成仙人掌再输出就可以了。
时间为 \(O(\sum( nm \log (nm)))\),可以过但是没有到最优复杂度。
复杂度更优做法
观察到边权只有 \(0\) 和 \(1\) ,因此我们可以使用 01 BFS 算法来在 \(O(n)\) 时间内求解最短路。
01 BFS 板子:Switch the lamp on 。
还要注意的是 01 BFS 只有在节点从 deque 里出来后才能判断是否抵达终点,因为如果在 push 时就判断,则会导致可能这个节点先更新了边权更大的节点,导致其先到终点就结束,而没有更新边权更小的节点导致算错最短路的情况。
我这里采用了数组模拟 deque ,为了减少常数,并且要注意这里数组没有办法直接开下,因此我们要用 vector 存。
坑点:vector 太大了,必须开在全局里,如果开在局部会爆栈导致 RE 。二维的 vector 在 clear 时要分维 clear ,无法一次 clear 掉全部。
时间为 \(O(\sum( nm ))\)。
01 BFS 代码
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pi;
int n,m;
int gox[]={0,0,1,-1};
int goy[]={1,-1,0,0};
int xx[]={1,1,-1,-1};
int yy[]={-1,1,-1,1};
bool check(int x,int y)
{
return (x>=1&&x<=n&&y>=1&&y<=m);
}
pi q[1500005];
vector<int>c[200005];//不能开在局部
vector<int>f[200005];
vector<pi>pre[200005];
vector<pi>cac;
int h,t;
void outp(int ex,int ey)
{
cout<<"YES"<<endl;
while((ex!=-1)&&(ey!=-1))
{
c[ex][ey]=0;
pi tmp=pre[ex][ey];
ex=tmp.first;
ey=tmp.second;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(c[i][j]==0)cout<<'#';
else cout<<'.';
}
cout<<endl;
}
}
void solve()
{
for(auto tmp:cac)
{
int x=tmp.first,y=tmp.second;
c[x][y]=0;
for(int i=0;i<4;i++)
{
int tx=x+gox[i],ty=y+goy[i];
if(check(tx,ty)&&c[tx][ty]==1)c[tx][ty]=-1;
}
}
h=750000,t=750000;
for(int i=1;i<=n;i++)
{
if(c[i][1]!=-1)
{
if(c[i][1]==0)q[--h]={i,1};
else q[t++]={i,1};
f[i][1]=c[i][1];
pre[i][1]={-1,-1};
}
}
while(t-h>0)
{
pi now=q[h++];
int x=now.first,y=now.second;
int w=f[x][y];
if(y>=m)//这里不能放在 push 时判断
{
outp(x,y);
return;
}
for(int i=0;i<4;i++)
{
int nx=xx[i]+x,ny=yy[i]+y;
if(check(nx,ny)&&f[nx][ny]==0x3f3f3f3f&&c[nx][ny]!=-1)
{
int nw=w+c[nx][ny];
f[nx][ny]=nw;
if(t-h<=0||nw<=f[q[h].first][q[h].second])q[--h]={nx,ny};
else q[t++]={nx,ny};
pre[nx][ny]={x,y};
}
}
}
cout<<"NO"<<endl;
}
int main()
{
int t;
cin>>t;
while(t--)
{
for(int i=0;i<=n;i++)//多维 vector 要逐维 clear ,不然会 CE 。
{
c[i].clear();
f[i].clear();
pre[i].clear();
}
cac.clear();
cin>>n>>m;
for(int i=1;i<=n;i++)
{
c[i].push_back(0);
f[i].push_back(0x3f3f3f3f);
pre[i].push_back({0,0});
for(int j=1;j<=m;j++)
{
char tmp;
cin>>tmp;
if(tmp=='#')cac.push_back({i,j});
c[i].push_back(1);
f[i].push_back(0x3f3f3f3f);
pre[i].push_back({0,0});
}
}
solve();
}
return 0;
}
Codeforces 1749E Cactus Wall 题解 [ 紫 ] [ 01 BFS ] [ 图论建模 ] [ 构造 ] [ adhoc ]的更多相关文章
- Codeforces Round #599 (Div. 1) B. 0-1 MST 图论
D. 0-1 MST Ujan has a lot of useless stuff in his drawers, a considerable part of which are his math ...
- Codeforces Round #599 (Div. 2) D. 0-1 MST(bfs+set)
Codeforces Round #599 (Div. 2) D. 0-1 MST Description Ujan has a lot of useless stuff in his drawers ...
- Codeforces Round #543 Div1题解(并不全)
Codeforces Round #543 Div1题解 Codeforces A. Diana and Liana 给定一个长度为\(m\)的序列,你可以从中删去不超过\(m-n*k\)个元素,剩下 ...
- Codeforces Round #545 Div1 题解
Codeforces Round #545 Div1 题解 来写题解啦QwQ 本来想上红的,结果没做出D.... A. Skyscrapers CF1137A 题意 给定一个\(n*m\)的网格,每个 ...
- Codeforces Round #539 Div1 题解
Codeforces Round #539 Div1 题解 听说这场很适合上分QwQ 然而太晚了QaQ A. Sasha and a Bit of Relax 翻译 有一个长度为\(n\)的数组,问有 ...
- [Codeforces Round #461 (Div2)] 题解
[比赛链接] http://codeforces.com/contest/922 [题解] Problem A. Cloning Toys [算法] 当y = 0 , 不可以 当 ...
- Codeforces 7E - Defining Macros 题解
目录 Codeforces 7E - Defining Macros 题解 前言 做法 程序 结尾 Codeforces 7E - Defining Macros 题解 前言 开始使用博客园了,很想写 ...
- Educational Codeforces Round 64 部分题解
Educational Codeforces Round 64 部分题解 不更了不更了 CF1156D 0-1-Tree 有一棵树,边权都是0或1.定义点对\(x,y(x\neq y)\)合法当且仅当 ...
- Educational Codeforces Round 64部分题解
Educational Codeforces Round 64部分题解 A 题目大意:给定三角形(高等于低的等腰),正方形,圆,在满足其高,边长,半径最大(保证在上一个图形的内部)的前提下. 判断交点 ...
- 【题解】284E. Coin Troubles(dp+图论建模)
[题解]284E. Coin Troubles(dp+图论建模) 题意就是要你跑一个完全背包,但是要求背包的方案中有个数相对大小的限制 考虑一个\(c_i<c_j\)的限制,就是一个\(c_i\ ...
随机推荐
- Educational Codeforces Round 155 (Rated for Div
B. Chips on the Board 题解:贪心 显然我们可以把题意转化为:对于任意一个\((i,j)\),我们可以花费\(a_{i,j}\)的代价占据第\(i\)行和第\(j\)列,求占据所有 ...
- Mybatis【11】-- Mybatis Mapper动态代理怎么写?
目录 1.回顾Mybatis执行sql的流程 2.mapper动态代理怎么写? 3.mapper动态代理怎么做的? 1.回顾Mybatis执行sql的流程 在之前的代码中我们的运行过程再梳理一下,首先 ...
- ZCMU-1111
与背包和动态规划有关(我认为) 采用dp数组存放吃掉i千克食物要用掉的钱 dp最开始要尽量的大方便过程中判断和最后的输出判断 实时更新dp,保留最小的钱 以前不知道的 printf函数可以这样用 fi ...
- 《JavaScript 模式》读书笔记(8)— DOM和浏览器模式1
在本书的前面章节中,我们主要集中关注于核心JavaScript(ECMAScript),而并没有太多关注在浏览器中使用JavaScript的模式.本章将探索一些浏览器特定的模式,因为浏览器是使用Jav ...
- 内网穿透之http代理服务器
在公网访问内网http服务可以用内网穿透工具,例如frp和nps等优秀工具.但我发现这类工具会在服务器启动不止一个端口,对于有些网络审查来说很容易发现在进行内网穿透.因此我想是否可以只在服务器启动一个 ...
- 在 .NET 环境下访问 SOAP 服务
在 .NET 环境下访问 SOAP 服务 SOAP 服务有着悠久的历史,目前仍然存在大量的 SOAP 服务,它是基于 HTTP 协议和 XML 技术的简单对象访问协议. 在 .NET Framewor ...
- 中电金信:金Gien乐道 | 4月要闻速览,精彩再回顾
中国电子党组副书记.总经理李立功一行调研中电金信 4月10日,中国电子党组副书记.总经理李立功一行赴中电金信进行调研,深入听取了中电金信经营发展情况.研发工作及"源启"行业 ...
- django推导流程
目录 一.纯手撸web框架 二.基于wsgiref模块 三.代码封装优化 四.动静态网页 五.jinja2模块 六.前端.后端.数据库三者联动 一.纯手撸web框架 1.web框架的本质 理解1:连接 ...
- Qt开源作品11-屏幕录制控件
一.前言 在平时的写作过程中,经常需要将一些操作动作和效果图截图成gif格式,使得涵盖的信息更全面更生动,有时候可以将整个操作过程和运行效果录制成MP4,但是文件体积比较大,而且很多网站不便于上传,基 ...
- Qt开源作品37-网络中转服务器
一.前言 用Qt做开发10年了,其中做过好多项目,基于现在web和移动互联网发展如此迅猛,大量的应用场景需要一个网络中转服务器,可以实现手机app或者其他客户端远程回控设备,现在物联网发展非常迅猛,这 ...