ACM-ICPC 2018 徐州赛区网络预赛 J. Maze Designer(LCA,最大生成树)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yz467796454/article/details/82704439

题目链接:https://nanti.jisuanke.com/t/31462

样例输入 
3 3
D 1 R 9
D 7 R 8
D 4 X 0
D 2 R 6
D 12 R 5
D 3 X 0
X 0 R 10
X 0 R 11
X 0 X 0
3
1 1 3 3
1 2 3 2
2 2 3 1
样例输出 
4
2
2

题意:n*m的矩阵,两点之间建墙需要一定的花费,现在需要你建墙,q个询问,每个询问给出两个点坐标,求两点之间路径唯一且花费最少的路径长度是多少。

思路: 两点间路径唯一,可以想到树,树上任意两点路径唯一,那么先建立所有的墙,然后拆除唯一路径上的墙,使得拆除的墙花费最大,反过来就是建墙的最少花费。所以先建立最大生成树,然后用两点的LCA求两点间的最小距离,就是答案。

代码参考:ACM-ICPC 2018 徐州赛区网络预赛 J. Maze Designer

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#define maxn 300005
using namespace std;

int n,m,fa[maxn];
priority_queue<pair<int, pair<int, int> > > edge;
int find(int p){
	if(fa[p]!=p)
		fa[p]=find(fa[p]);
	return fa[p];
}
void unionset(int p,int q){
	fa[q]=p;
}
//LCA.
int pre[32][maxn]; //Ancestor Nodes.
int dep[maxn]; //Depth of Nodes.
vector<int> adj[maxn];
void dfs(int u, int p){
	pre[0][u] = p;
	for (int i=0;i<adj[u].size();i++){
		int v=adj[u][i];
		if(v!=p) {
			dep[v]=dep[u]+1;
			dfs(v,u);
		}
	}
}
void init_lca(int n){
    dfs(0, -1);
    for (int k = 0; k < 20; k++) {
        for (int v = 0; v < n; v++) {
            if (pre[k][v]) pre[k + 1][v] = pre[k][pre[k][v]];
        }
    }
}
int lca(int u, int v){
    if (dep[u] > dep[v]) swap(u, v);
    for (int k = 0; k < 20; k++) {
        if ((dep[v] - dep[u]) & (1 << k)) v = pre[k][v];
    }
    if (u == v) return u;
    for (int k = 19; k >= 0; k--) {
        if (pre[k][u] != pre[k][v]) {
            u = pre[k][u];
            v = pre[k][v];
        }
    }
    return pre[0][u];
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	int tot=0;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			char s[10],ss[10];
			int a,b;
			scanf("%s%d%s%d",s,&a,ss,&b);
			if(s[0]=='D'){
				int u=i*m+j;
				int v=i*m+m+j;
				edge.push(make_pair(a, make_pair(u, v)));
			}
			if(ss[0]=='R'){
				int u=i*m+j;
				int v=i*m+j+1;
				edge.push(make_pair(b, make_pair(u, v)));
			}
		}
	}
	for(int i=0;i<=n*m;i++)fa[i]=i;
	while(!edge.empty()){
		pair<int,pair<int,int> >e=edge.top();
		edge.pop();
		int u = e.second.first;
		int v = e.second.second;
		int fu=find(u),fv=find(v);
		if(fu!=fv){
			unionset(fu,fv);
			adj[u].push_back(v);
			adj[v].push_back(u);
		}
	}
	int q;
	scanf("%d",&q);
	init_lca(n*m);
	while(q--){
		int x1,x2,y1,y2;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		x1--;y1--;x2--;y2--;
		int u=x1*m+y1;
		int v=x2*m+y2;
		printf("%d\n",dep[u]+dep[v]-2*dep[lca(u,v)]);
	}
	return 0;
}

这份代码我是用以前写最小生成树的写法写的,不知道为什么一直错,区别也仅仅是这份代码用了结构体,然后对w排序,不知道为什么一直只能过8组样例

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<vector>
#define maxn 300005
using namespace std;

 
struct node{
	int x,y,w;
}e[maxn];
 
int n,m,fa[maxn];
 
bool cmp(const node &a,const node &b){
	return a.w>b.w;
}
int find(int p){
	if(fa[p]!=p)
		fa[p]=find(fa[p]);
	return fa[p];
}
void unionset(int p,int q){
	fa[q]=p;
}
//LCA.
int pre[32][maxn]; //Ancestor Nodes.
int dep[maxn]; //Depth of Nodes.
vector<int> adj[maxn];
void dfs(int u, int p){
	pre[0][u] = p;
	for (int i=0;i<adj[u].size();i++){
		int v=adj[u][i];
		if(v!=p) {
			dep[v]=dep[u]+1;
			dfs(v,u);
		}
	}
}
void init_lca(int n){
    dfs(0, -1);
    for (int k = 0; k < 20; k++) {
        for (int v = 0; v < n; v++) {
            if (pre[k][v]) pre[k + 1][v] = pre[k][pre[k][v]];
        }
    }
}
int lca(int u, int v){
    if (dep[u] > dep[v]) swap(u, v);
    for (int k = 0; k < 20; k++) {
        if ((dep[v] - dep[u]) & (1 << k)) v = pre[k][v];
    }
    if (u == v) return u;
    for (int k = 19; k >= 0; k--) {
        if (pre[k][u] != pre[k][v]) {
            u = pre[k][u];
            v = pre[k][v];
        }
    }
    return pre[0][u];
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	int tot=0;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			char s[10],ss[10];
			int a,b;
			scanf("%s%d%s%d",s,&a,ss,&b);
			if(s[0]=='D'){
				int u=i*m+j;
				int v=i*m+m+j;
				e[tot].x=u;e[tot].y=v;e[tot].w=a;
				tot++;
			}
			if(ss[0]=='R'){
				int u=i*m+j;
				int v=i*m+j+1;
				e[tot].x=u;e[tot].y=v;e[tot].w=b;
				tot++;
			}
		}
	}
	for(int i=0;i<=n*m;i++)fa[i]=i;
	sort(e,e+tot,cmp);
	int j=0;
	while(j<tot){
		int m1=e[j].x,m2=e[j].y;
		int sn1=find(m1),sn2=find(m2);
		if(sn1!=sn2){
			unionset(sn1,sn2);
			adj[m1].push_back(m2);
			adj[m2].push_back(m1);
		}
		j++;
	}
	int q;
	scanf("%d",&q);
	init_lca(n*m);
	while(q--){
		int x1,x2,y1,y2;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		x1--;y1--;x2--;y2--;
		int u=x1*m+y1;
		int v=x2*m+y2;
		printf("%d\n",dep[u]+dep[v]-2*dep[lca(u,v)]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/yz467796454/article/details/82704439