zoukankan      html  css  js  c++  java
  • 最强大脑 题解

    题目链接: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的位置了。如下图

    (从红色街区交费以后可以跳到周围的任意蓝色街区。)
    现在的问题很简单。有三个居民,她们分别是zhb的maze,分别叫做X,Y,Z。现在她们决定聚在一起玩找zhb玩(….),于是想往其中一人的位置集合。但由于zhb太抠门了,不给报销路费,所以告诉你3个maze的坐标,求往哪里集合大家需要花的费用总和最低。
    Zhb:如果你完美解决了这个问题,就授予你“最强大脑”称号。

    输入
    输入的第一行包含两个整数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);
    }

  • 相关阅读:
    一些 Codeforce Content 补题记录
    如何设置IDEA代码风格为Google风格,使用Google风格format
    python学习第十篇——while 的灵活运用
    Python学习第九篇——while和for的区别
    python学习之第八篇——字典嵌套之字典中嵌套字典
    python学习第七篇——字典访问键与值
    Python学习第六篇——字典中的键和值
    Python学习第五篇——如何访问字典
    Python学习第四篇——列表访问与判定
    [Leetcode] Maximum depth of binary tree二叉树的最大深度
  • 原文地址:https://www.cnblogs.com/genius-garden/p/4992431.html
Copyright © 2011-2022 走看看