题解 P1902 刺杀大使

题解 P1902 刺杀大使

首先注意到,只需要到达一个开关,就可以开启所有开关(打开所有门)

所以我们就可以想到,我们要寻找一条从任意 \(1-m\) 开关(因为访问一个开关就可以开启所有开关,详情见看ps)到达 \(1-m\) 门的所有路径中伤害数最大值最小路径

很容易就想到了,最大值最小,明显是二分答案(伤害数),二分每条路径中的伤害数最大值

  • 如果路径中的伤害数大于二分的答案,说明此答案不满足,就将二分的答案调大,以此找到满足条件的路径
  • 如果满足条件,就试着找到更小的答案,将二分答案调小,寻找满足条件的路径

ps:看起来可能要遍历所有的开关来找到到达门的路径,实际上,因为开关的伤害数为 \(0\) ,所以可以直接从第一个开关开始 \(bfs\) ,借此访问到每个开关的同时,寻找路径的可能性,累计的最大伤害数都是 \(0\)


// #Tyrue#
#include<map>
#include<queue>
#include<cstdio>
#include<string>
#include<string.h>
#include<iostream>
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0' && ch<='9')
        x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int N=1e3+10;
int T,n,m,l=1e9,r=-1e9;
int a[N][N],vis[N][N];
int dx[5]{0,0,0,1,-1},dy[5]{0,1,-1,0,0};
struct Node{
    int x,y;
};
queue<Node> q;
bool bfs(int xz){
    memset(vis,0,sizeof vis);
    while(!q.empty()){
        q.pop();
    }
    q.push((Node){1,1});
    vis[0][0]=1;
    while(!q.empty()){
        Node f=q.front();
        q.pop();
        if(f.x==n){
            return 1;
        }
        for(int i=1;i<=4;i++){
            int xx=f.x+dx[i],yy=f.y+dy[i];
            if(xx<=n && xx>=1 && yy<=m && yy>=1 && !vis[xx][yy] && a[xx][yy]<=xz){
                q.push((Node){xx,yy});
                vis[xx][yy]=1;
            }
        }
    }
    return 0;
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            a[i][j]=read();
            l=min(l,a[i][j]);
            r=max(r,a[i][j]);
        }
    }
    int ans;
    // printf("%d %d\n",l,r);
    while(l<r){
        int mid=(l+r)>>1;
        // printf("%d %d %d\n",l,r,mid);
        if(bfs(mid)){
            r=mid;
            // ans=mid;
        }else{
            // printf("%d\n",l);
            l=mid+1;
        }
    }
    printf("%d",l); 
    return 0;
}
posted @ 2022-11-30 17:16  Tyrue  阅读(28)  评论(0编辑  收藏  举报