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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章