2018徐州网络预选赛 J 题 Maze Designer 【思维 + 最大生成树 + LCA】

版权声明:本文为博主原创文章,喜欢就点个赞吧 https://blog.csdn.net/Anxdada/article/details/82588065

传送门
题意:给定一个n*m的矩阵, 除了边界, 其他相邻的边都有一个代价, 现在我们需要在这个矩形中选择一些边封起来, 代价就是开始输入的代价, 我们要让封起来的代价和尽量的小, 并且封起来后, 矩阵中任意两点之间的最短路径是唯一的, 现在不告诉你具体是怎样封的(但是这个矩形已经进行了封墙的操作), 然后q个询问, 每次询问两个点, 他们在这个已经处理过的矩形中的最短路径是多少.

思路: 其实想到了就是个水题, 我们很明显可以将这个矩形看成一幅图, 边的代价就是输入的代价, 然后就是要让这个矩形中的任意两个点之间最短路径唯一, 实际上在图中就是一颗树啊!!! , 然后结合代价要最小, 所以我们建图后做最大生成树就是实际上矩阵的形式了, 也就是没有的边实际上就是我们要封的边. 然后询问就是询问树上两点之间的距离, 这个就可以用LCA做.. 所以实际上看通路径唯一就是做生成树, 基本上这道题就是一个水题了…. !!!

AC Code

const int maxn = 500*500 + 5;
struct node {
    int to, next;
}e[maxn<<1];
struct edge {
    int u, v, w;
    bool operator < (const edge &_) const {
        return w > _.w;
    }
}s[maxn<<1];
int head[maxn], cnt;
int fa[maxn];
int n, m, k;
int up[maxn][23], dep[maxn];
void init() {
    cnt = 0; Fill(head, -1);
    for (int i = 1 ; i <= n*m ; i ++) fa[i] = i;
}
void add(int u, int v) {
    e[cnt] = node{v, head[u]};
    head[u] = cnt++;
}
int Find(int x) {
    return fa[x] == x ? fa[x] : fa[x] = Find(fa[x]);
}
void work() {
    for (int i = 1 ; i <= k ; i ++) {
        int u = Find(s[i].u), v = Find(s[i].v);
        if (u != v) {
            fa[u] = v;
            add(s[i].u, s[i].v);
            add(s[i].v, s[i].u);
        }
    }
}
void dfs(int u,int fa,int d) {
    dep[u] = d + 1;
    for(int i = 1 ; i < 20 ; i ++) {
        up[u][i] = up[up[u][i-1]][i-1];
    }
    for(int i = head[u] ; ~i ; i = e[i].next) {
        int to = e[i].to;
        if(to == fa) continue;
        up[to][0] = u;
        dfs(to, u, d+1);
    }
}
int LCA_BZ(int u,int v) {
    if(dep[u] < dep[v]) swap(u,v);
    int k = dep[u] - dep[v];
    for(int i = 19 ; i >= 0 ; i --) {
        if((1<<i) & k) {
            u = up[u][i];
        }
    }
    if(u == v) return u;
    for(int i = 19 ; i >= 0 ; i --) {
        if(up[u][i] != up[v][i]){
            u = up[u][i];
            v = up[v][i];
        }
    }
    return up[u][0];
}
void solve() {
    scanf("%d%d", &n, &m); k = 0; init();
    for (int i = 1 ; i <= n*m ; i ++) {
        char op[5]; int x;
        int tt = 2;
        while(tt--) {
            scanf("%s%d", op, &x);
            if (op[0] == 'X') continue;
            if (op[0] == 'R') s[++k] = edge{i, i+1, x};
            else s[++k] = edge{i, i+m, x};
        }
    }
    sort(s+1, s+1+k);
    work();
    dfs(1, -1, -1);
    int q; scanf("%d", &q);
    while(q--) {
        int x1, y1, x2, y2;
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        int u = (x1-1) * m + y1;
        int v = (x2-1) * m + y2;
        printf("%d\n", dep[u] + dep[v] - 2*dep[LCA_BZ(u, v)]);
    }
}

猜你喜欢

转载自blog.csdn.net/Anxdada/article/details/82588065