题意:
有一个n*m的方格
每个小格子之间有一道墙 给定建这道墙的价格
要求建一些墙 使得方格内的任意两个小方格之间都只有唯一的一条路径 并且要使这个建墙方式花费最小
现在给定q组坐标 问这对坐标的路径长度
思路:树的性质之一是 结点之间只有唯一的一条路径
通过建立墙来构出一条路径,也可以反过来理解,将墙全部建好,然后再删除一些墙
这样的话 找出最大生成树 因为这样保证了建的墙的价格最优
然后再在最大生成树里面找 两个点的简单路径
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mp make_pair #define fi first #define se second const int N =1e6+3; int n,m; struct tree{ int cnt,y[N],z[N],head[N],nxt[N]; void clc(){ cnt= 0 ; memset(y,0,sizeof(y)); memset(z,0,sizeof(y)); memset(head,0,sizeof(y)); memset(nxt,0,sizeof(y)); } void add(int a,int b,int c){ y[++cnt] = b;z[cnt]=c; nxt[cnt] = head[a]; head[a] = cnt; } }e,q; struct node{ int u,v,c; friend bool operator < (node a,node b){ return a.c>b.c; } }; node edge[N]; int all; int pre[N]; int find(int x){ return x==pre[x]?x:pre[x]=find(pre[x]); } bool same(int a,int b){ return find(a)==find(b); } void Union(int a,int b){ pre[find(a)]=find(b); } void krucal(){ sort(edge,edge+all); for(int i=1;i<=n;++i)pre[i]=i; for(int i=0;i<all;++i){ node tmp = edge[i]; if(!same(tmp.u,tmp.v)){ e.add(tmp.u,tmp.v,1); e.add(tmp.v,tmp.u,1); Union(tmp.u,tmp.v); } } } int dis[N],vis[N]; int ans[N]; int fxa; void dfs(int t,int pre){ for(int i=e.head[t];i;i=e.nxt[i]){ if(e.y[i]==pre)continue; dis[e.y[i]] = dis[t]+e.z[i]; dfs(e.y[i],t); } } void lca(int t,int fa){ for(int i=e.head[t];i;i=e.nxt[i]){ if(e.y[i]==fa)continue; lca(e.y[i],t); pre[e.y[i]] = t; } vis[t]=1; for(int i=q.head[t];i;i=q.nxt[i]){ if(vis[q.y[i]] && !ans[q.z[i]]){ ans[q.z[i]] = dis[t]+dis[q.y[i]]-2*dis[find(q.y[i])]; } } } int main(){ while(cin>>n>>m){ q.clc();e.clc(); memset(ans,0,sizeof(ans)); memset(vis,0,sizeof(vis)); all = 0 ; char d[22],r[22];int v1,v2; n = n*m; for(int i=1;i<=n;++i){ scanf("%s %d %s %d",d,&v1,r,&v2); if(d[0]=='D'){ edge[all++] = node{i,i+m,v1}; } if(r[0]=='R'){ edge[all++] =node{i,i+1,v2}; } } int a[4]; int ask; scanf("%d",&ask); for(int i=1;i<=ask;++i){ for(int j=0;j<4;++j)scanf("%d",&a[j]); int u= a[0]*m-m+a[1];int v = a[2]*m-m+a[3]; q.add(u,v,i);q.add(v,u,i); } krucal(); dis[1]=0; dfs(1,0); for(int i =1;i<=n;++i)pre[i]=i; lca(1,0); for(int i=1;i<=ask;++i)cout<<ans[i]<<endl; } return 0; }