题目链接:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=1252
最强大脑 |
难度级别:C; 运行时间限制:20000ms; 运行空间限制:262144KB; 代码长度限制:2000000B |
试题描述
|
zhb国是一个传说中的国度,国家的居民叫做最强(chang)大脑(diao)。Zhb国是一个N×M的矩形方阵,每个格子代表一个街区。
然而zhb国是没有交通工具的。居民大脑(diao)们完全靠地面的弹射装置来移动。 每个街区都装有弹射装置。使用弹射装置是需要支付一定费用的。而且每个弹射装置都有自己的弹射能力。 我们设第i行第j列的弹射装置有Aij的费用和Bij的弹射能力。并规定有相邻边的格子间距离是1。那么,任何居民大脑(diao)都只需要在(i,j)支付Aij的费用就可以任意选择弹到距离不超过Bij的位置了。如下图 (从红色街区交费以后可以跳到周围的任意蓝色街区。) |
输入
|
输入的第一行包含两个整数N和M,分别表示行数和列数。
接下来是2个N×M的自然数矩阵,为Aij和Bij 最后一行六个数,分别代表X,Y,Z所在地的行号和列号。 |
输出
|
第一行输出一个字符X、Y或者Z。表示最优集合地点。
第二行输出一个整数,表示最小费用。 如果无法集合,只输出一行NO |
输入示例
|
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 |
输出示例
|
Z
15 |
其他说明
|
20% N, M ≤ 10; Bij ≤ 20
40% N, M ≤ 100; Bij ≤ 20 100% 1 ≤ N, M ≤ 150; 0 ≤ Bij ≤ 109; 0 ≤ Aij ≤ 1000 |
那天,我开心的发现WZJ同学做了那道“最强大脑”,作死地打开了看(因为WZJ没刷对),想了想,写了两个小时,终于AC了。怒甩标程八条街。
原理:用二维线段树(WZJ同学说像KD树)表示一个区域,如果可以到达父节点表示的区域,那么一定就可以到达该节点所有的子孙节点,于是,具体的看代码吧。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define INF 2147483647
using namespace std;
inline int read()
{
int x=0,t=1,c;
while(!isdigit(c=getchar()))if(c=='-')t=-1;
while(isdigit(c))x=x*10+c-'0',c=getchar();
return x*t;
}
bool is_in(int left,int down,int right,int up,int x,int y,int r)
{
if(left>right||down<up)return false;
int X,Y,distx,disty;
if(x<left)X=0;
else if(x>=left&&x<=right)X=1;
else if(x>right)X=2;
if(y<up)Y=0;
else if(y>=up&&y<=down)Y=1;
else if(y>down)Y=2;
if(X==0)
{
if(Y==0)
{
distx=left-x;
disty=up-y;
if(distx+disty<=r)return true;
else return false;
}
if(Y==1)
{
if(left-x<=r)return true;
else return false;
}
if(Y==2)
{
distx=left-x;
disty=y-down;
if(distx+disty<=r)return true;
else return false;
}
}
if(X==1)
{
if(Y==0)
{
if(up-y<=r)return true;
else return false;
}
if(Y==1)
{
return true;
}
if(Y==2)
{
if(y-down<=r)return true;
else return false;
}
}
if(X==2)
{
if(Y==0)
{
distx=x-right;
disty=up-y;
if(distx+disty<=r)return true;
else return false;
}
if(Y==1)
{
if(x-right<=r)return true;
else return false;
}
if(Y==2)
{
distx=x-right;
disty=y-down;
if(distx+disty<=r)return true;
else return false;
}
}
}
bool is_all_in(int left,int down,int right,int up,int x,int y,int r)
{
if(left>right||down<up)return false;
int distx,disty;
distx=abs(left-x);
disty=abs(down-y);
if(distx+disty>r)return false;
disty=abs(y-up);
if(distx+disty>r)return false;
distx=abs(x-right);
disty=abs(down-y);
if(distx+disty>r)return false;
disty=abs(y-up);
if(distx+disty>r)return false;
return true;
}
int first[140000],target[10000000],next[10000000],value[10000000],countn=1;
void AddEdge(int u,int v,int length)
{
target[countn]=v;
value[countn]=length;
next[countn]=first[u];
first[u]=countn++;
}
int from,posx,posy,r,v,A[160][160],B[160][160];
void build(int o,int left,int down,int right,int up,bool cut)
{
if(left==right&&up==down)return;
int lc=o<<1,rc=lc+1,m;
AddEdge(o,lc,0);
AddEdge(o,rc,0);
if((cut||left==right)&&up!=down)
{
m=up+down>>1;
build(lc,left,m,right,up,!cut);
build(rc,left,down,right,m+1,!cut);
}
else
{
m=left+right>>1;
build(lc,left,down,m,up,!cut);
build(rc,m+1,down,right,up,!cut);
}
}
void update(int o,int left,int down,int right,int up,bool cut)
{
if(is_all_in(left,down,right,up,posx,posy,r))
{
AddEdge(from,o,v);
return;
}
int lc=o<<1,rc=lc+1,m;
if((cut||left==right)&&up!=down)
{
m=up+down>>1;
if(is_in(left,m,right,up,posx,posy,r))update(lc,left,m,right,up,!cut);
if(is_in(left,down,right,m+1,posx,posy,r))update(rc,left,down,right,m+1,!cut);
}
else
{
m=left+right>>1;
if(is_in(left,down,m,up,posx,posy,r))update(lc,left,down,m,up,!cut);
if(is_in(m+1,down,right,up,posx,posy,r))update(rc,m+1,down,right,up,!cut);
}
}
int query(int o,int left,int down,int right,int up,bool cut)
{
if(left==right&&up==down)return o;
int lc=o<<1,rc=lc+1,m;
if((cut||left==right)&&up!=down)
{
m=up+down>>1;
if(posy<=m)return query(lc,left,m,right,up,!cut);
else return query(rc,left,down,right,m+1,!cut);
}
else
{
m=left+right>>1;
if(posx<=m)return query(lc,left,down,m,up,!cut);
else return query(rc,m+1,down,right,up,!cut);
}
}
struct State
{
int pos,cost;
bool operator < (const State &b)const
{
return cost>b.cost;
}
}take,put;
priority_queue<State> PQ;
int fastest[140000],N,M;
int Dijkstra(int x0,int y0,int x1,int y1)
{
memset(fastest,127,sizeof(fastest));
while(!PQ.empty())PQ.pop();
int s,t;
posx=x0;
posy=y0;
s=query(1,1,N,M,1,0);
posx=x1;
posy=y1;
t=query(1,1,N,M,1,0);
put.pos=s;
put.cost=0;
PQ.push(put);
while(!PQ.empty())
{
take=PQ.top();
PQ.pop();
if(fastest[take.pos]<take.cost)continue;
if(take.pos==t)
{
return take.cost;
}
for(int i=first[take.pos];i;i=next[i])
{
if(fastest[target[i]]>take.cost+value[i])
{
fastest[target[i]]=take.cost+value[i];
put.pos=target[i];
put.cost=fastest[put.pos];
PQ.push(put);
}
}
}
return -1;
}
int main()
{
N=read(),M=read();
build(1,1,N,M,1,0);
for(int i=1;i<=N;i++)
{
for(int j=1;j<=M;j++)
{
B[i][j]=read();
}
}
for(int i=1;i<=N;i++)
{
for(int j=1;j<=M;j++)
{
A[i][j]=read();
if(B[i][j])
{
posx=j;
posy=i;
r=B[i][j];
v=A[i][j];
from=query(1,1,N,M,1,0);
update(1,1,N,M,1,0);
}
}
}
int y0=read(),x0=read(),y1=read(),x1=read(),y2=read(),x2=read();
int XtoY,YtoX,XtoZ,ZtoX,YtoZ,ZtoY,ans=INF;
char place='N';
XtoY=Dijkstra(x0,y0,x1,y1);
YtoX=Dijkstra(x1,y1,x0,y0);
XtoZ=Dijkstra(x0,y0,x2,y2);
ZtoX=Dijkstra(x2,y2,x0,y0);
YtoZ=Dijkstra(x1,y1,x2,y2);
ZtoY=Dijkstra(x2,y2,x1,y1);
if(~YtoX&&~ZtoX)
{
if(YtoX+ZtoX<ans)
{
place='X';
ans=YtoX+ZtoX;
}
}
if(~ZtoY&&~XtoY)
{
if(ZtoY+XtoY<ans)
{
place='Y';
ans=XtoY+ZtoY;
}
}
if(~XtoZ&&~YtoZ)
{
if(XtoZ+YtoZ<ans)
{
place='Z';
ans=XtoZ+YtoZ;
}
}
if(place=='N')puts("NO");
else printf("%c
%d",place,ans);
}