P1902 刺杀大使

暴力方法是把所有路径全部跑一遍,现在只考虑((0, 0))位置的门分别走向第n - 1行的所有门的路径,假设只向上向右走,那么(0, 0)到(n - 1, k)的路径条数为(C_{n}^{k}),所以从(0, 0)到第n - 1行所有的门的路径条数总和为(C_{n}^{0} + C_{n}^{1} + ... + C_{n}^{m - 1}),极限情况下总和为(C_{1000}^{0} + C_{1000}^{1} + ... + C_{1000}^{999} = 2^{1000} - 1),但是这个数字一定比真正的总路径条数小,因为没有向下走,回头啥的的路径,所以没法用暴力

思路:二分答案x,并且通过bfs检查能否找到这样一条路径使得路径上的最大值满足≤x,如果能找到这条路径,那么说明所有比x大的值都能够找到这样一条路径,所以答案有二段性,因为是整数二分,所以一定能够找到x的最小值使得找到一条路径使得路径上的最大值=x

#include<iostream>
#include<queue>
#include<cstring>

using namespace std;

const int N = 1010;

#define PII pair<int, int>
#define x first
#define y second

int g[N][N], st[N][N];
int n, m;
int dx[] = {0, 0, 1, -1}, dy[] = {-1, 1, 0, 0};

int check(int val){
    memset(st, 0, sizeof st);
    queue<PII> q;
    for(int i = 0; i < m; i ++){
        if(st[1][i] == 0 && g[1][i] <= val){
            st[0][i] = 1;
            q.push({0, i});
            while(q.size()){
                PII h = q.front();
                q.pop();
                for(int j = 0; j < 4; j ++){
                    int x = h.x + dx[j], y = h.y + dy[j];
                    if(x < 0 || x >= n || y < 0 || y >= m || st[x][y] || g[x][y] > val) continue;
                    st[x][y] = 1;
                    q.push({x, y});
                    if(x == n - 2) return 1; 
                }
            }
        }
    }
    return 0;
}

int main(){
    cin >> n >> m;
    
    for(int i = 0; i < n; i ++)
        for(int j = 0; j < m; j ++) 
            cin >> g[i][j];
    
    int l = 0, r = 1000;
    while(l < r){
        int mid = l + r >> 1;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    
    cout << l << endl;
    
    return 0;
}
原文地址:https://www.cnblogs.com/tomori/p/15255614.html