P1902 刺殺大使(BFS+二分答案)

P1902 刺殺大使

(From:Luogu)
題目描述

伊朗伊斯蘭革命衛隊(某恐怖組織)正在策劃一起刺殺行動,他們的目標是沙特駐美大 使朱拜爾。他們來到了沙特駐美使館,準備完成此次刺殺,要進入使館首先必須通過使館前 的防禦迷陣。

迷陣由 n*m 個相同的小房間組成,每個房間與相鄰四個房間之間有門可通行。在第 n 行的 m 個房間裏有 m 個機關,這些機關必須全部打開纔可以進入大使館。而第 1 行的 m 個 房間有 m 扇向外打開的門,是迷陣的入口。除了第 1 行和第 n 行的房間外,每個房間都被 使館的安保人員安裝了激光殺傷裝置,將會對進入房間的人造成一定的傷害。第 i 行第 j 列 造成的傷害值爲 p[i][j](第 1 行和第 n 行的 p 值全部爲 0)。

現在伊斯蘭革命衛隊打算以最小傷害代價進入迷陣,打開全部機關,顯然,他們可以選 擇任意多的人從任意的門進入,但必須到達第 n 行的每個房間。一個士兵受到的傷害值爲他 到達某個機關的路徑上所有房間的傷害值中的最大值,整個部隊受到的傷害值爲所有士兵的 傷害值中的最大值。現在,這個恐怖組織掌握了迷陣的情況,他們需要提前知道怎麼安排士 兵的行進路線可以使得整個部隊的傷害值最小。

輸入輸出格式

輸入格式:
第一行有兩個整數 n,m,表示迷陣的大小。

接下來 n 行,每行 m 個數,第 i 行第 j 列的數表示 p[i][j]。

輸出格式:
輸出一個數,表示最小傷害代價。

輸入輸出樣例

輸入樣例#1:
4 2
0 0
3 5
2 4
0 0
輸出樣例#1:
3
說明

50%的數據,n,m<=100;

100%的數據,n,m<=1000,p[i][j]<=1000。

思路

這個題目簡單來說就是在矩陣上找到一條從第一行到最後一行的路徑,使路徑上節點的“最大值最小”,看到這個字眼,我們直接就能想到二分答案的做法。
我們能比較容易的想到我們去二分一個所謂的路徑最大值,所以我們只需要檢驗二分出來的路徑最大值是否能夠成立即可,而我們檢驗路徑的方法就是用BFS。
在做BFS的時候,爲了防止狀態空間過大,我們用一個bool數組來存是否可達某位置。最後檢驗一下是否能夠到達第n行的任意點即可。
這裏我們需要注意一下對於整數而言的二分技巧,就是用一個ans記錄最近當前的可行解。

代碼

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<queue>
using namespace std;
int i,j,m,n;
int mo[4][3]={{-1,0},{1,0},{0,-1},{0,1}};
int a[1001][1001];
int b[1001][1001];
queue<int>p,q;
int le,ri;
int r()
{
    char ch=getchar();
    int ans=0,f=1;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        ans*=10;
        ans+=ch-'0';
        ch=getchar();
    }
    return ans*f;
}

bool check(int x)
{
    memset(b,0,sizeof(b));
    for(i=1;i<=m;i++)
    p.push(1),q.push(i),b[1][i]=1;
    int nx,ny,sx,sy;
    while(!q.empty())
    {
        sx=p.front(),sy=q.front();
        for(i=0;i<4;i++)
        {
            nx=sx+mo[i][0];
            ny=sy+mo[i][1];
            if(nx<=n&&nx>0&&ny<=m&&ny>0)
            {
                if(a[nx][ny]>x||b[nx][ny])
                continue;
                p.push(nx),q.push(ny);
                if(nx==n)
                return 1;
            }
        }
        q.pop();
        p.pop();
    }
    return 0;
}

int main()
{
//  freopen("in.txt","r",stdin);
    n=r();m=r();
    for(i=1;i<=n;i++)
    for(j=1;j<=m;j++)
    {
        a[i][j]=r();
        ri=max(ri,a[i][j]); 
    }
    int mid,ans;
    while(le<=ri)
    {
        mid=le+ri;
        mid>>=1;
        if(check(mid))
        {
            ans=mid;
            ri=mid-1;
        }
        else
        le=mid+1;
    }

    printf("%d",mid);

    return 0;
}
/*
6 5
0 0 0 0 0
10 154 52 2 2
2 2 2 24 21
2 5 85 63 2
2 35 686 32 5
0 0 0 0 0
*/

這裏寫圖片描述

發佈了131 篇原創文章 · 獲贊 102 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章