1. 程式人生 > >【極值問題】【CF1063B】 Labyrinth

【極值問題】【CF1063B】 Labyrinth

!= -i ron ans 極值 define 包括 建圖 emp

傳送門

Description

給你一個\(n~\times~m\)的矩陣,一開始你在第\(r\)行第\(c\)列。你的上下移動不受限制,向左最多移動\(x\)次,向右最多移動\(y\)次。求你最多能到多少個點。包括起始點。

Input

第一行是\(n\)\(m\),代表矩陣規模。

第二行是\(r\)\(c\),代表你的位置

第三行是\(x\)\(y\),代表移動限制

下面\(n\)行每行\(m\)個字符,有且僅有‘.‘和‘‘兩種。如果第\(i\)行第\(j\)列是‘‘代表你不能經過這個點。

Output

輸出一行一個數代表能到的最多點數

Sample Input

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

Sample Output

10

Hint

\(For~All:\)

\(0~\leq~n,m,r,c~\leq~2000\),\(0~\leq~x,y~\leq~10^9\)

Solution

樸素的\(bfs\)顯然是對的,可以狀態太多存不下。

考慮如果從\((sx,sy)\)點到一個點\((x,y)\)時,假設共向右走了\(r\)步,向左走了\(l\)步,顯然\(r-l\)是一個定值。具體的,\(r-l~=~y-sy\)。於是,對於任意一個目標\((x,y)\),發現\(l\)事實上與\(r\)線性正相關。對於一個點,顯然到該點的\(r\)越小越好,同時由於\(l\)\(r\)線性正相關,所以最小化\(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

當題設需要最小化多個變量時,不妨考慮變量間的相關關系,從此轉化成單變量的極值問題。

當邊權只有\(0\)\(1\)的時候,可以考慮使用\(0/1bfs\),省去dij的log。

【極值問題】【CF1063B】 Labyrinth