BZOJ2143 飞飞侠 & [校内NOIP2018模拟20181026] 最强大脑
Time Limit: 50 Sec Memory Limit: 259 MB
Description
飞飞国是一个传说中的国度,国家的居民叫做飞飞侠。飞飞国是一个N×M的矩形方阵,每个格子代表一个街区。然而飞飞国是没有交通工具的。飞飞侠完全靠地面的弹射装置来移动。每个街区都装有弹射装置。使用弹射装置是需要支付一定费用的。而且每个弹射装置都有自己的弹射能力。我们设第i行第j列的弹射装置有Aij的费用和Bij的弹
射能力。并规定有相邻边的格子间距离是\(1\)。那么,任何飞飞侠都只需要在(i,j)支付Aij的费用就可以任意选择弹
到距离不超过Bij的位置了。如下图
(从红色街区交费以后可以跳到周围的任意蓝色街区。)现在的问题很简单。有三个飞飞侠,分别叫做X,Y,Z。
现在它们决定聚在一起玩,于是想往其中一人的位置集合。告诉你3个飞飞侠的坐标,求往哪里集合大家需要花的
费用总和最低。
Input
输入的第一行包含两个整数\(N\)和\(M\),分别表示行数和列数。
接下来是2个N×M的自然数矩阵,为\(B_{i,j}\)和\(A_{i,j}\)
最后一行六个数,分别代表X,Y,Z所在地的行号和列号。
\(1\leq N,M\leq 150\);\(0\leq B_{i,j}\leq 10^9\);\(0\leq A_{i,j}\leq1000\)
Output
第一行输出一个字符X、Y或者Z。表示最优集合地点。
第二行输出一个整数,表示最小费用。如果无法集合,只输出一行NO
Sample Input
4 4
0 0 0 0
1 2 2 0
0 2 2 1
0 0 0 0
5 5 5 5
5 5 5 5
5 5 5 5
5 5 5 5
2 1 3 4 2 2
Sample Output
Z
15
Solution
嗯这道题的算法还是很有意思的,有时间还要再好好品味一下,真的是很新奇。
一眼最短路啊,但是如果我们直接跑Dijkstra的话(什么,这个世道你还敢用SPFA,更何况这还是网格图),转移数量太多了,肯定会T掉。
所以我们考虑一下转化,在一个点投射,相当于给了他一个\(B[i][j]\)的能量,然后每走一个消耗一个点数的能量。
那么我们设\(dist[i][j][k]\)表示走到\((i,j)\)这个点,还剩\(k\)点的能量的情况。那么转移就是这样的:
这样然后再加上Dijsktra的堆的复杂度就是\(O(n^3\log (n^3))\)的。比较卡常,在学校OJ上过不去,BZOJ上好像能过。
我们考虑优化。后面的学长们讨论了各种各样的优化,比如什么线段树优化建边,线段树进行转移,并查集优化最短路什么的。
但是这些我都不太会,所以只能自己YY出了一个实测效果很好的优化。显然Dijkstra里面每一次进行操作的点的\(dist\)值是单调不减的,所以如果遇到这样的情况我们可以直接跳过,不去转移:同一个点,如果已经操作过比现在这个状态能量要多的点,那么显然现在这个状态没有那个优,就可以不去转移了。我们只需要每次都转移那些能量大于曾经转移过的同一个点的能量值最大值的状态。这样的话,我们可以优化掉很多没有用的状态,实测效果不错,在BZOJ上排到了第二页,不过还是比不上那些神一样的并查集优化最短路。
但是遗憾的是,好像这样的复杂度还是没有变的,大家也许可以叉一叉。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define lowbit(x) ((x)&(-(x)))
#define REP(i,a,n) for(register int i=(a);i<=(n);++i)
#define PER(i,a,n) for(register int i=(a);i>=(n);--i)
#define FEC(i,x) for(register int i=head[x];i;i=g[i].ne)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
namespace io{
const int SIZE=(1<<21)+1;char ibuf[SIZE],*iS,*iT,obuf[SIZE],*oS=obuf,*oT=oS+SIZE-1,c,qu[55];int f,qr;
#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),(iS==iT?EOF:*iS++)):*iS++)
inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;}
inline void putc(char x){*oS++=x;if(oS==oT)flush();}
template<class I>inline void read(I &x){for(f=1,c=gc();c<'0'||c>'9';c=gc())if(c=='-')f=-1;for(x=0;c<='9'&&c>='0';c=gc())x=x*10+(c&15);x*=f;}
template<class I>inline void write(I x){if(!x)putc('0');if(x<0)putc('-'),x=-x;while(x)qu[++qr]=x%10+'0',x/=10;while(qr)putc(qu[qr--]);}
inline void print(const char *s){while(*s!='\0')putc(*s++);}
inline void scan(char *s){for(c=gc();c<=' ';c=gc());for(;c>' ';c=gc())*(s++)=c;*s='\0';}
struct Flusher_{~Flusher_(){flush();}}io_flusher_;
}//orz laofudasuan
using io::read;using io::putc;using io::write;using io::print;
typedef long long ll;typedef unsigned long long ull;
template<typename A,typename B>inline bool SMAX(A&x,const B&y){return x<y?x=y,1:0;}
template<typename A,typename B>inline bool SMIN(A&x,const B&y){return y<x?x=y,1:0;}
const int N=150+3,INF=0x3f3f3f3f,fx[]={0,0,1,0,-1},fy[]={0,1,0,-1,0};
int n,m,b[N][N],a[N][N],dist[N][N][N<<1],vis[N][N],flag1,flag2,X1,Y1,X2,Y2,X3,Y3,ans=INF,get[4][4];char ans2;//错误笔记:get[4][4]开成了get[3][3]
struct Node{int x,y,en,dist;inline bool operator<(const Node&a)const{return dist>a.dist;}};priority_queue<Node>q;
inline void Dijkstra(Node S,Node T1,Node T2,int &flag1,int &flag2){
memset(dist,0x3f,sizeof(dist));memset(vis,-1,sizeof(vis));while(!q.empty())q.pop();
dist[S.x][S.y][b[S.x][S.y]]=a[S.x][S.y];q.push(Node{S.x,S.y,b[S.x][S.y],a[S.x][S.y]});flag1=flag2=0;
while(!q.empty()){
Node p=q.top();q.pop();if(vis[p.x][p.y]>=p.en)continue;int flag=(vis[p.x][p.y]==-1);SMAX(vis[p.x][p.y],p.en);
if(p.x==T1.x&&p.y==T1.y&&!flag1)flag1=p.dist;if(p.x==T2.x&&p.y==T2.y&&!flag2)flag2=p.dist;if(flag1&&flag2)return;
for(register int i=0;i<=4;++i){
Node f=Node{p.x+fx[i],p.y+fy[i],p.en-1,p.dist};if(f.x<1||f.x>n||f.y<1||f.y>m)continue;
if(vis[f.x][f.y]<=f.en&&dist[f.x][f.y][f.en]>p.dist){
dist[f.x][f.y][f.en]=dist[p.x][p.y][p.en];
q.push(f);
}
}
if(flag){Node f=Node{p.x,p.y,b[p.x][p.y],p.dist+a[p.x][p.y]};
if(vis[f.x][f.y]<=f.en&&dist[f.x][f.y][f.en]>p.dist+a[p.x][p.y]){
dist[f.x][f.y][f.en]=p.dist+a[p.x][p.y];
q.push(f);
}}
}if(!flag1)flag1=INF;if(!flag2)flag2=INF;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("zhber.in","r",stdin);freopen("zhber.out","w",stdout);
#endif
read(n),read(m);
for(register int i=1;i<=n;++i)for(register int j=1;j<=m;++j)read(b[i][j]),SMIN(b[i][j],max(max(i-1+j-1,n-i+j-1),max(i-1+m-j,n-i+m-j)));
for(register int i=1;i<=n;++i)for(register int j=1;j<=m;++j)read(a[i][j]);
read(X1),read(Y1),read(X2),read(Y2),read(X3),read(Y3);
Dijkstra(Node{X1,Y1},Node{X2,Y2},Node{X3,Y3},get[1][2],get[1][3]);
Dijkstra(Node{X2,Y2},Node{X1,Y1},Node{X3,Y3},get[2][1],get[2][3]);
Dijkstra(Node{X3,Y3},Node{X1,Y1},Node{X2,Y2},get[3][1],get[3][2]);
if(SMIN(ans,get[2][1]+get[3][1]))ans2='X';
if(SMIN(ans,get[1][2]+get[3][2]))ans2='Y';
if(SMIN(ans,get[1][3]+get[2][3]))ans2='Z';
if(ans2<'X')print("NO\n");else putc(ans2),putc('\n'),write(ans),putc('\n');
}