I. Intersections
题意:
n行,m列,n * m个交点,当我们处于交点(i,j),
如果当前时间位于[k * aij + k * bij , (k+1) * aij + k * bij ),我们可以上下移动
如果当前处于[(k+1)* aij + k * bij , (k+1) * aij + (k+1) * bij ],我们可以左右移动
也可以选择不动
cij表示从(i,j)移动到(i,j+1)的时间
wij表示从(i,j)移动到(i+1,j)的时间
问从(xs,ys)到(xt,yt)的最少时间是多少?
题解:
这个题肯定是最短路方向,但是和一般最短路不一样,因为你的方向选择受时间的限制,其实也不难,但是思维不要被限制,要放开想
我们先从时间下手,这两个时间区间合在一起就是[k * aij + k * bij, (k+1) * aij + (k+1) * bij ],一个周期就是(aij+bij),那么也就可以这样理解,给一个时间tim,x = tim%(aij+bij),如果x小于aij,说明当前时间就位于第一区间,如果大于等于aij,(也就是到达bij的区域)就在第二区间
tim的求法
ll tim = now.z % (a[x][y] + b[x][y]);
现在我们开始考虑路径
f[i][j]到点i,j的最短时间
如果我们要从(x,y)移动到(x-1,y),怎么行动?首先花费是固定的w[i-1][j],关键是什么时间段移动,
如果当前时间在第一时间段,在这个区间里,我们是可以上下移动的,也就是可以立刻行动,所以就是直接求最短路f[x - 1][y] = f[x][y] + w[x - 1][y];
如何当前时间在第二时间段,我们只能左右移动,根本不能到达上面,那怎么办,这个情况放弃?错了,这个时间段不能向上移动,但是我们说了(aij+bij)是一个周期,所以我们完全可以等到下一个周期的第一个时间段再向上移动,等待时间(即原地不动)
ll Tim = a[x][y] + b[x][y] - tim;//这是纯等待时间
f[x - 1][y] = f[x][y] + w[x - 1][y] + Tim;
也就是第一种情况的基础上算上等待时间
这是向上走的情况,还有向下,左,右三种情况,一次列出即可,用dij跑最短路就OK了
这样一看题目简单多了
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <unordered_map>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;typedef long long ll;
const int maxn = 505;
ll a[maxn][maxn],b[maxn][maxn],c[maxn][maxn],w[maxn][maxn];
ll f[maxn][maxn];
int vis[maxn][maxn];int n,m,sx,sy,ex,ey;struct Node {int x,y;ll z;bool operator < (const Node&rhs) const {return z > rhs.z;}
};void dij(int sx,int sy) {priority_queue<Node>q;q.push({sx,sy,0});f[sx][sy] = 0;while(!q.empty()) {Node now = q.top();q.pop();int x = now.x;int y = now.y;if(vis[x][y]) continue;vis[x][y] = 1;ll tim = now.z % (a[x][y] + b[x][y]);if(x > 1) { //往上走if(tim < a[x][y]) {//可以上下移动 if(f[x - 1][y] > f[x][y] + w[x - 1][y]) {f[x - 1][y] = f[x][y] + w[x - 1][y];q.push({x - 1,y,f[x - 1][y]});}} else {//只能左右移动,如果想往上走需要再等Tim这段时间 ll Tim = a[x][y] + b[x][y] - tim;if(f[x - 1][y] > f[x][y] + w[x - 1][y] + Tim) {f[x - 1][y] = f[x][y] + w[x - 1][y] + Tim;q.push({x - 1,y,f[x - 1][y]});}}}//下面同理与上 if(x < n) { //往下走if(tim < a[x][y]) {if(f[x + 1][y] > f[x][y] + w[x][y]) {f[x + 1][y] = f[x][y] + w[x][y];q.push({x + 1,y,f[x + 1][y]});}} else {ll Tim = a[x][y] + b[x][y] - tim;if(f[x + 1][y] > f[x][y] + w[x][y] + Tim) {f[x + 1][y] = f[x][y] + w[x][y] + Tim;q.push({x + 1,y,f[x + 1][y]});}}}if(y > 1) { //往左走if(tim < a[x][y]) {ll Tim = a[x][y] - tim;if(f[x][y - 1] >= f[x][y] + c[x][y - 1] + Tim) {f[x][y - 1] = f[x][y] + c[x][y - 1] + Tim;q.push({x,y - 1,f[x][y - 1]});}} else {if(f[x][y - 1] > f[x][y] + c[x][y - 1]) {f[x][y - 1] = f[x][y] + c[x][y - 1];q.push({x,y - 1,f[x][y - 1]});}}}if(y < m) { //往右走if(tim < a[x][y]) {ll Tim = a[x][y] - tim;if(f[x][y + 1] >= f[x][y] + c[x][y] + Tim) {f[x][y + 1] = f[x][y] + c[x][y] + Tim;q.push({x,y + 1,f[x][y + 1]});}} else {if(f[x][y + 1] > f[x][y] + c[x][y]) {f[x][y + 1] = f[x][y] + c[x][y];q.push({x,y + 1,f[x][y + 1]});}}}}
}int main() {scanf("%d%d%d%d%d%d",&n,&m,&sx,&sy,&ex,&ey);for(int i = 1;i <= n;i++) {for(int j = 1;j <= m;j++) {scanf("%lld",&a[i][j]);}}for(int i = 1;i <= n;i++) {for(int j = 1;j <= m;j++) {scanf("%lld",&b[i][j]);}}for(int i = 1;i <= n;i++) {for(int j = 1;j <= m - 1;j++) {scanf("%lld",&c[i][j]);}}for(int i = 1;i <= n - 1;i++) {for(int j = 1;j <= m;j++) {scanf("%lld",&w[i][j]);}}memset(f,0x3f,sizeof(f));dij(sx,sy);printf("%lld\n",f[ex][ey]);return 0;
}