【极值问题】【CF1063B】 Labyrinth

传送门

Description

给你一个n × m的矩阵,一开始你在第r行第c列。你的上下移动不受限制,向左最多移动x次,向右最多移动y次。求你最多能到多少个点。包括起始点。

Input

第一行是nm,代表矩阵规模。

第二行是rc,代表你的位置

第三行是xy,代表移动限制

下面n行每行m个字符,有且仅有'.'和''两种。如果第i行第j列是''代表你不能经过这个点。

Output

输出一行一个数代表能到的最多点数

Sample Input

4 5
3 2
1 2
.....
.***.
...**
*....

Sample Output

10

Hint

For All:

0  n,m,r,c  2000,0  x,y  109

Solution

朴素的bfs显然是对的,可以状态太多存不下。

考虑如果从(sx,sy)点到一个点(x,y)时,假设共向右走了r步,向左走了l步,显然rl是一个定值。具体的,rl = ysy。于是,对于任意一个目标(x,y),发现l事实上与r线性正相关。对于一个点,显然到该点的r越小越好,同时由于lr线性正相关,所以最小化r的同时,l已经被最小化了。于是可以直接建图跑最短路,所有向右的边权为1,其他边权为0。跑完后扫描整个地图就可以判断合法性了。

这里的一个新姿势是0/1bfs。当边权只有0/1时,可以使用双端队列进行bfs,具体的,当当前边的权值时0时,将终点压入队首,否则压入队尾。考虑这么做的正确性:易证任意一时刻队列中的点dist差值不超过1。于是正确性显然。0/1bfs的复杂度为O(V+E)。相比dij少了一个log。

Code

#include<queue>
#include<cstdio>
#include<cstring>
#define rg register
#define ci const int
#define cl const long long int

typedef long long int ll;

namespace IO{
    char buf[110];
}

template <typename T>
inline void qr(T &x) {
    rg char ch=getchar(),lst=' ';
    while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();
    while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    if(lst == '-') x=-x;
}

template <typename T>
inline void qw(T x,const char aft,const bool pt) {
    if(x < 0) {putchar('-');x=-x;}
    rg int top=0;
    do {
        IO::buf[++top]=x%10+'0';
    } while(x/=10);
    while(top) putchar(IO::buf[top--]);
    if(pt) putchar(aft);
}

template <typename T>
inline T mmax(const T a,const T b) {return a > b ? a : b;}
template <typename T>
inline T mmin(const T a,const T b) {return a < b ? a : b;}
template <typename T>
inline T mabs(const T a) {return a < 0 ? -a : a;}

template <typename T>
inline void mswap(T &a,T &b) {
    T _temp=a;a=b;b=_temp;
}

const int maxn = 2010;

const int fx[]={0,-1,0,1};
const int fy[]={1,0,-1,0};
const int fv[]={1,0,0,0};

int n,m,sx,sy,x,y;
int MU[maxn][maxn];
char mp[maxn][maxn];

std::deque<int>Qx,Qy;

int main() {
    qr(n);qr(m);qr(sx);qr(sy);qr(x);qr(y);
    for(rg int i=1;i<=n;++i) scanf("%s",mp[i]+1);
    memset(MU,0x3f,sizeof MU);
    MU[sx][sy]=0; Qx.push_front(sx);Qy.push_front(sy);
    while(!Qx.empty()) {
        int hx=Qx.front(),hy=Qy.front();Qx.pop_front();Qy.pop_front();
        for(rg int i=0;i<4;++i) {
            int dx=hx+fx[i],dy=hy+fy[i];
            if((dx > n) || (dy > m) || (!dx) || (!dy) || (mp[dx][dy] == '*') || (MU[dx][dy] <= MU[hx][hy]+fv[i])) continue;
            MU[dx][dy]=MU[hx][hy]+fv[i];
            if(i) {Qx.push_front(dx);Qy.push_front(dy);}
            else {Qx.push_back(dx);Qy.push_back(dy);}
        }
    }
    rg int _ans=0;
    for(rg int i=1;i<=n;++i) {
        for(rg int j=1;j<=m;++j) if(mp[i][j] != '*') {
            if((MU[i][j] <= y) && ((MU[i][j]-j+sy) <= x)) ++_ans;
        }
    }
    qw(_ans,'\n',true);
    return 0;
}

Summary

当题设需要最小化多个变量时,不妨考虑变量间的相关关系,从此转化成单变量的极值问题。

当边权只有01的时候,可以考虑使用0/1bfs,省去dij的log。

posted @   一扶苏一  阅读(390)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示