链接

题解

首先很容易想到对每个点暴力跑Dijkstra,但是这样边数是 \(N^4\) 的,考虑优化

发现每次松弛的时候,都要把整个地图扫一遍,每个节点都要重复扫很多次,如果我们在一个点不会再被更新的时候,用并查集跳过去,那么就可以降低复杂度

如果将点插入堆时,比较 \(dis[i]+w[i]\) 而不是 \(dis[i]\) ,这样可以保证一个点被更新后不会再一次被更新。

现在证明上述结论,以及这样做仍然可以得到正确的最短路。

假设点 \(x\) 已经得到了最短路,证明用该点更新的 \(y\) 也得到了最短路

反证,假设存在路径 $ x’ \to y$ 使 \(dis[y]\) 更小,且在 \(x\) 更新 \(y\) 之后,那么有 \(dis[x']+w[x']< dis[x]+w[x]\) ,因为 \(x'\) 在 \(x\) 之后,有 \(dis[x']+w[x']\ge dis[x]+w[x]\),两式矛盾,运用数学归纳法,可知上述结论成立,以及起点 \(s\) 到每一点的最短路径就是 \(dis[i]\)

因此,用并查集合并已经更新过的点,再一次扫描到的时候,直接跳过即可,边数优化成 \(N^2\)

复杂度 \(O(N^2logN)\)

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i(a);i<=(b);++i)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
inline int read(){char c,p=0;int w;
while(isspace(c=getchar()));if(c=='-')p=1,c=getchar();w=c&15;
while(isdigit(c=getchar()))w=w*10+(c&15);return p?-w:w;
}
template<typename T,typename U>inline bool smin(T&x,const U&y){return x>y?x=y,1:0;}
template<typename T,typename U>inline bool smax(T&x,const U&y){return x<y?x=y,1:0;}
const int N=155;
int n,m,a[N][N],b[N][N],d[3][N][N],vis[N][N],fa[N][N];
priority_queue< pair<int,pii> >q;
#define xx first
#define yy second
inline int find(int*f,int x){return f[x]?f[x]=find(f,f[x]):x;}
inline void solve(int d[N][N],pii s){
REP(i,1,n)REP(j,1,m)d[i][j]=1e9;
memset(vis,0,sizeof vis);
memset(fa,0,sizeof fa);
d[s.xx][s.yy]=0;
q.push(make_pair(-a[s.xx][s.yy],s));fa[s.xx][s.yy]=s.yy+1;
while(!q.empty()){
pii u=q.top().yy;q.pop();
const int&x=u.xx,&y=u.yy;
if(vis[x][y])continue;vis[x][y]=1;
int lx=max(1,x-b[x][y]),rx=min(n,x+b[x][y]);
REP(i,lx,rx){
int t=b[x][y]-abs(i-x),ly=max(1,y-t),ry=min(m,y+t);
for(int j=find(fa[i],ly);j<=ry;j=find(fa[i],j)){
if(smin(d[i][j],d[x][y]+a[x][y]))q.push(make_pair(-d[i][j]-a[i][j],pii(i,j)));
fa[i][j]=j+1;
} }
}
}
pii s[3];
const char ss[]="XYZ";
int main(){
n=read(),m=read();
REP(i,1,n)REP(j,1,m)b[i][j]=read();
REP(i,1,n)REP(j,1,m)a[i][j]=read();
REP(i,0,2)s[i].xx=read(),s[i].yy=read(),solve(d[i],s[i]);
int dis=1e9;
int ans=-1;
REP(i,0,2){
#define d(p) d[p][s[i].xx][s[i].yy]
if(smin(dis,d(0)+d(1)+d(2)))ans=i;
}
if(~ans)printf("%c\n%d",ss[ans],dis);
else puts("NO");
return 0;
}

最新文章

  1. final 评论 I
  2. 移动Web单页应用开发实践——页面结构化
  3. Android开发在使用第三方推送的时候出现INSTALL_FAILED_VERSION_DOWNGRADE
  4. P2P直播、点播技术学习经验
  5. ASP.NET MVC- 使用PageList.Mvc分页
  6. DHCP Option 60 的理解
  7. springMVC学习(1)
  8. C#进程间通信--API传递参数(SendMessage)
  9. setStyleSheet来设定窗口部件的样式
  10. UIWebView 使用要注意的几点
  11. 自然语言处理高手_相关资源_开源项目(比如:分词,word2vec等)
  12. Windows 10 IoT Serials 9 – 如何利用IoTCoreAudioControlTool改变设备的音频设备
  13. C++map类型 之 简单介绍
  14. 配置SQL Server on Linux(1)
  15. 从零开始一起学习SLAM | 掌握g2o边的代码套路
  16. HTML的Tomcat
  17. android与php使用base64加密的字符串结果不一样解决方法
  18. 莫烦keras学习自修第一天【keras的安装】
  19. layer.open窗口自适应问题
  20. gulp常用方法

热门文章

  1. django uWSGI nginx搭建一个web服务器 确定可用
  2. Frame Stacking ZOJ 1083,poj 1128
  3. sicily 1004. 简单哈希
  4. 基于jquery 的find()函数和children()函数的区别
  5. P3066 [USACO12DEC]逃跑的BarnRunning Away From… 树上差分_树上倍增
  6. iOS下调用元素的focus方法,input元素不聚焦,键盘不弹起的问题
  7. 在MAC上安装lxml到Python3
  8. caioj 1072 动态规划入门(二维一边推5:最长公共子序列 LCSS加强版)
  9. 【Codeforces Round #465 (Div. 2) C】Fifa and Fafa
  10. javaweb——登陆权限过滤器的编写