BZOJ 2143 飞飞侠(分层最短路)
飞飞国是一个N×M的矩形方阵,每个格子代表一个街区。然而飞飞国是没有交通工具的。飞飞侠完全靠地面的弹射装置来移动。每个街区都装有弹射装置。使用弹射装置是需要支付一定费用的。而且每个弹射装置都有自己的弹射能力。我们设第i行第j列的弹射装置有Aij的费用和Bij的弹射能力。并规定有相邻边的格子间距离是1。那么,任何飞飞侠都只需要在(i,j)支付Aij的费用就可以任意选择弹到距离不超过Bij的位置了。现在的问题很简单。有三个飞飞侠,分别叫做X,Y,Z。现在它们决定聚在一起玩,于是想往其中一人的位置集合。告诉你3个飞飞侠的坐标,求往哪里集合大家需要花的费用总和最低。
考虑直接建图,点n*m,边n*n*m*m,不可行。
考虑将整个矩形再加一维,表示高度,那么对于最下面一层的点,连向的边是他对应Bij的高度,然后其他的点就向相邻位置的下一层连边。
这样点n*m*(maxBij),边n*m*(maxBij)*5.
实际上maxBij只要超过(n+m)的时候就可以到达图上任意一点,所以实际上maxBij只会<=(n+m).
然后对于三个飞飞侠跑三遍最短路即可。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <bitset> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-8 # define MOD 1000000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FDR(i,a,n) for(int i=a; i>=n; --i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; inline int Scan() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } inline void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=155; //Code begin.... int A[N][N], B[N][N], ps[5][2]={0,0,-1,0,1,0,0,-1,0,1}; int n, m, node[3]; LL dist[N*N*N*3], d[3][3]; bool vis[N*N*N*3]; struct qnode{ int v; LL c; qnode(int _v=0, LL _c=0):v(_v),c(_c){} bool operator<(const qnode &r)const{return c>r.c;} }; priority_queue<qnode>que; const LL P=1LL<<60; int get_id(int x, int y, int z){return n*m*(z-1)+(y-1)*n+(x-1);} void Dijkstra(int nn, int start){ int u, x, y, z, px, py, pz, id; mem(vis,false); FOR(i,0,nn) dist[i]=P; dist[node[start]]=0; while (!que.empty()) que.pop(); que.push(qnode(node[start],0)); qnode tmp; while (!que.empty()) { if (dist[node[0]]!=P && dist[node[1]]!=P && dist[node[2]]!=P) break; tmp=que.top(); que.pop(); u=tmp.v; if (vis[u]) continue; vis[u]=true; z=u/(n*m)+1; y=(u%(n*m))/n+1; x=u%(n*m)%n+1; if (z==1) { pz=min(n+m,1+B[x][y]); id=get_id(x,y,pz); if (!vis[id]&&dist[id]>dist[u]+A[x][y]) dist[id]=dist[u]+A[x][y], que.push(qnode(id,dist[id])); } else { FOR(i,0,4) { px=x+ps[i][0]; py=y+ps[i][1]; if (px<=0||px>n||py<=0||py>m) continue; id=get_id(px,py,z-1); if (!vis[id]&&dist[id]>dist[u]) dist[id]=dist[u], que.push(qnode(id,dist[id])); } } } FOR(i,0,2) d[start][i]=dist[node[i]]; } int main () { int x, y; n=Scan(); m=Scan(); FOR(i,1,n) FOR(j,1,m) B[i][j]=Scan(); FOR(i,1,n) FOR(j,1,m) A[i][j]=Scan(); FOR(i,0,2) x=Scan(), y=Scan(), node[i]=get_id(x,y,1); FOR(i,0,2) Dijkstra(n*m*(n+m+1),i); LL ans=P; int p; FOR(i,0,2) if (ans>d[0][i]+d[1][i]+d[2][i]) ans=d[0][i]+d[1][i]+d[2][i], p=i; if (ans==P) puts("NO"); else { if (p==0) puts("X"); else if (p==1) puts("Y"); else puts("Z"); printf("%lld\n",ans); } return 0; }