2018 German Collegiate Programming Contest (GCPC 18) M - Mountaineers(启发式合并)

题目链接:https://codeforces.com/gym/102021/attachments

题意:现在有个地图由nmn*m个方格组成,每个方格上有个数字,代表在这个点的海拔高度,现在qq次询问,每次询问给出两个点,你需要找到一条路径可以由一个点走到另一个点并且要求这条路径上的最高海拔要尽可能的小,输出每次询问的最小的最大高度。从一个点只能走到这个点的四个方向。

解题心得:这个题只能将点加入然后用并查集维护可以走到的点这样才能满足复杂度,在放入点的时候需要将每个点按照高度排序,从小到大放入,在合并并查集的时候需要启发式合并。



#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1010;

int num[maxn][maxn], n, m, q, que[maxn][maxn], ans[maxn*maxn];
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
struct Point {
    int x, y, va;
    bool operator < (const Point & p) const {
        return va < p.va;
    }
};

struct Node {
    int fa;
    set<int> se;
}node[maxn*maxn];

vector <Point> ve;

int Hash(int x, int y) {
    return (x-1)*m + y;
}

void init() {
    scanf("%d%d%d",&n, &m, &q);
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=m;j++) {
            scanf("%d", &num[i][j]);
            ve.push_back({i, j, num[i][j]});
            node[Hash(i, j)].fa = Hash(i, j);
        }
    }
    sort(ve.begin(), ve.end());

    for(int i=1;i<=q;i++) {
        int x1, x2, y1, y2;
        scanf("%d%d%d%d",&x1, &y1, &x2, &y2);
        if(x1 == x2 && y1 == y2) {
            ans[i] = num[x1][y1];
            continue;
        }
        que[x1][y1] = i;
        que[x2][y2] = i;
        node[Hash(x1, y1)].se.insert(i);
        node[Hash(x2, y2)].se.insert(i);
    }

}

bool checke(int x,int y) {
    if(x <= 0 || y <= 0 || x > n || y > m) return true;
    return false;
}

int find(int x) {
    if(x == node[x].fa) return x;
    else return node[x].fa = find(node[x].fa);
}

void merge(int x, int y, int Ans) {
    int fx = find(x);
    int fy = find(y);

    if(fx == fy) return ;

    int cnt1 = node[fx].se.size(), cnt2 = node[fy].se.size();
    if(cnt1 <= cnt2) {
        set <int> :: iterator iter, iter2;
        for(iter=node[fx].se.begin();iter!=node[fx].se.end();iter++) {
            int va = (*iter);
            iter2 = node[fy].se.find(va);
            if(iter2 == node[fy].se.end()) {
                node[fy].se.insert(va);
            } else {
                ans[va] = Ans;
                node[fy].se.erase(iter2);
            }
        }

        node[fx].fa = node[fy].fa;
    } else {
        set <int> :: iterator iter, iter2;
        for(iter=node[fy].se.begin();iter!=node[fy].se.end();iter++) {
            int va = (*iter);
            iter2 = node[fx].se.find(va);
            if(iter2 == node[fx].se.end()) {
                node[fx].se.insert(va);
            } else {
                ans[va] = Ans;
                node[fx].se.erase(iter2);
            }
        }

        node[fy].fa = node[fx].fa;
    }
}

void solve() {
    for(int i=0;i<ve.size();i++) {
        Point now = ve[i];
        int va = now.va;
        int nx, ny;
        for(int i=0;i<4;i++) {
            nx = now.x + dir[i][0];
            ny = now.y + dir[i][1];
            if(checke(nx, ny)) continue;
            if(num[nx][ny] > num[now.x][now.y]) continue;

            int num1 = Hash(now.x, now.y);
            int num2 = Hash(nx, ny);

            merge(num1, num2, va);
        }
    }
}

int main() {
    //    freopen("1.in.txt", "r", stdin);
    init();
    solve();
    for(int i=1;i<=q;i++) {
        printf("%d\n", ans[i]);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章