版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}