洛谷P2658

我在洛谷第一次发个题解,管理员居然把这题的题解通道关了。。。。
看到好像没有优先队列的题解,来水一手

思路

  • 形似A* 却不是A*
  • 只需要求出其中一个点到其他点的D系数,所有D系数的最大值即是答案。

数学推理:如果有三个点a,b,c,a到b的难度系数为x,a到c的难度系数为d,显然从c到b可以从a经过,难度系数就是x和y较大的一个。
也就是说这是一个连通图,我们要求的是连通图中所有边权最大的值

  • 利用优先队列,先搜索难度系数小的,再由小的系数递推

这个方法唯一可能存在的问题就是:
难度系数小+更大的难度系数组合
和难度系数大+难度系数大(小)的组合(但是都比上面这个更大的难度系数小)
答案应该是第二个
那么当我们用优先队列搜索时,刚开始确实是从较小的开始,但是在更新的时候会把较大的也一起更新
那么后面先从队列里出来的肯定是第二个
说了这么多也不知道大家听懂没有

直接上代码吧,虽然不会有二分那么快,但是优先队列优化也是可以过的

代码

#include <iostream>
#include <utility>
#include <queue>
#include <cmath>
using namespace std;
typedef long long ll;
#define fi(i, a, b) for (int i = a; i <= b; ++i)
#define fr(i, a, b) for (int i = a; i >= b; --i)
#define x first
#define y second
#define sz(x) ((int)(x).size())
#define pb push_back
using pii = pair<int, int>;
//#define DEBUG
int n, m, stax, stay, count, res;
bool vis[505][505];//记录是否访问过
int flag[505][505];//标记是否是路标
int moun[505][505];//初始海拔数组
int dx[4] = {1, -1, 0, 0};//方向向量
int dy[4] = {0, 0, 1, -1};
struct car
{
    int x, y, D;
    bool operator<(const car &p) const
    {
        return D > p.D;
    }
};
int bfs(int x, int y)
{
    priority_queue<car> pri;
    pri.push({x, y, 0});
    while (!pri.empty())
    {
        car temp = pri.top();
        int x = temp.x, y = temp.y;
        // cout << x << " " << y << " " << temp.D << endl;Debug
        pri.pop();
        vis[x][y] = true;
        if (flag[x][y])//如果是个路标,下次就不会再访问了
        {
            flag[x][y] = 0;
            count--;
            res = max(res, temp.D);
            if (count == 0)
                return res;
        }
        fi(i, 0, 3)
        {
            int p = x + dx[i];
            int q = y + dy[i];
            if (p <= n && p >= 1 && q <= m && q >= 1 && !vis[p][q])
            {
                int r = abs(moun[x][y] - moun[p][q]);
                r = max(temp.D, r);
                pri.push({p, q, r});
            }
        }
    }
    return res;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> m;
    fi(i, 1, n) fi(j, 1, m) cin >> moun[i][j];
    fi(i, 1, n) fi(j, 1, m)
    {
        cin >> flag[i][j];
        if (flag[i][j])
            count++, stax = i, stay = j;
    }//记录所有路标的数量,并且从最后一个路标开始
    cout << bfs(stax, stay) << endl;
#ifdef DEBUG
    //freopen(D:\in.txt,r,stdin);
#endif
    return 0;
}
posted @ 2022-02-04 17:23  Sun-Wind  阅读(65)  评论(0编辑  收藏  举报