zoukankan      html  css  js  c++  java
  • 题解 P2981 【[USACO10FEB]奶牛在冰Cows on Ice】

    楼上的思路都是从一个石头找跳到另一个石头的路径,但其实这题可以对于上下左右四个方向分别做一个虚拟节点,然后只需要找虚拟节点左边的虚拟节点就行了

    问题是:不会用set怎么办???

    其实可以发现用vector二分可以实现同样的操作(虽然长得不行而且还各种wa)

    vector存图的方法:

    分别存下x和y方向的石头,然后用vec_x和vec_y存四个方向的虚拟节点

    作为一个懒人,负数是最大的折磨.将每个点加上1e9能有效避免负数

    然后,对每个方向判断一次左边最多能走到多远.这里是往上的判断

    long long find_up(long long x, long long y){
      string going = to_string(x);
      if (!mp_horizontal[going].size()) return -1; //这里面没东西
      if (!sorted_hori[going]) {sort(mp_horizontal[going].begin(),mp_horizontal[going].end());sorted_hori[going] = true;}//先把他排序才能二分
      long long le = 0, ri = mp_horizontal[going].size()-1;
      while(le<ri-1){
        long long mid = (le+ri)/2;
        if (mp_horizontal[going][mid]<=y) le = mid;
        else ri = mid;
      }//裸的二分
      if (mp_horizontal[going][le]>y && !between_y(mp_horizontal[going][le],y,going)) return mp_horizontal[going][le];
      if (mp_horizontal[going][ri]>y && !between_y(mp_horizontal[going][ri],y,going)) return mp_horizontal[going][ri];
      return -1;//between_y是查找两点之间是否有石头
    }
    

    现在来讲讲between_y.between_y的意义是确认虚拟节点之间不会有石头.这里我们同样用二分实现
    以下是between_y,between_x同理

    bool between_y(long long l, long long r, string ptr){
      string going = ptr;
      if (!stone_x[going].size()) return false;//没东西
      if (l>r) swap(l,r);
      if (!sorted_x[going]) {sort(stone_x[going].begin(),stone_x[going].end());sorted_x[going] = true;}
      long long le = 0, ri = stone_x[going].size()-1;
    
      while(le<ri-1){
        long long mid = (le+ri)/2;
    
        if (between(l,r,stone_x[going][mid])) return true;
        if (r>stone_x[going][mid]) le = mid;//二分
        else ri = mid;
      }
      return between(l,r,stone_x[going][le])||between(l,r,stone_x[going][ri]);//between定义为比left大且比right小
    }
    

    注意这题由于是map和vector存图,unordered_map也是一个不错的选择

    完整代码:

    #include <iostream>
    #include <algorithm>
    #include <unordered_map>
    #include <cstdio>
    #include <vector>
    #include <queue>
    using namespace std;
    #define pp pair<long long,long long>
    #define f first
    #define s second
    long long n,sx,sy,ex,ey;
    vector<int> vec_x,vec_y,st_x,st_y;
    unordered_map<string, bool> sorted_x,sorted_y,sorted_hori,sorted_vert;
    unordered_map<string,vector<long long> > mp_vertical,mp_horizontal,stone_x,stone_y;
    unordered_map<string,long long> vis;
    bool between(long long x, long long y, long long ptr){
      return x<=ptr && y>=ptr;
    }//就是懒得每次都这么打
    bool between_x(long long l, long long r, string ptr){
      string going = ptr;
      if (!stone_y[going].size()) return false;
      if (l>r) swap(l,r);
      if (!sorted_y[going]) {sort(stone_y[going].begin(),stone_y[going].end());sorted_y[going] = true;}
      long long le = 0, ri = stone_y[going].size()-1;
      while(le<ri-1){
        long long mid = (le+ri)/2;
        if (between(l,r,stone_y[going][mid])) return true;
        if (r<stone_y[going][mid]) ri = mid;
        else le = mid;
      }
      return between(l,r,stone_y[going][le])||between(l,r,stone_y[going][ri]);
    }//注意between_x是指y不变,所以这里要用stone_y.
    bool between_y(long long l, long long r, string ptr){
      string going = ptr;
      if (!stone_x[going].size()) return false;
      if (l>r) swap(l,r);
      if (!sorted_x[going]) {sort(stone_x[going].begin(),stone_x[going].end());sorted_x[going] = true;}
      long long le = 0, ri = stone_x[going].size()-1;
    
      while(le<ri-1){
        long long mid = (le+ri)/2;
    
        if (between(l,r,stone_x[going][mid])) return true;
        if (r>stone_x[going][mid]) le = mid;
        else ri = mid;
      }
      return between(l,r,stone_x[going][le])||between(l,r,stone_x[going][ri]);
    }//y方向查找
    long long find_up(long long x, long long y){
      string going = to_string(x);
      if (!mp_horizontal[going].size()) return -1;
      if (!sorted_hori[going]) {sort(mp_horizontal[going].begin(),mp_horizontal[going].end());sorted_hori[going] = true;}
      long long le = 0, ri = mp_horizontal[going].size()-1;
      while(le<ri-1){
        long long mid = (le+ri)/2;
        if (mp_horizontal[going][mid]<=y) le = mid;
        else ri = mid;
      }
      if (mp_horizontal[going][le]>y && !between_y(mp_horizontal[going][le],y,going)) return mp_horizontal[going][le];
      if (mp_horizontal[going][ri]>y && !between_y(mp_horizontal[going][ri],y,going)) return mp_horizontal[going][ri];
      return -1;
    }//往上
    long long find_down(long long x, long long y){
      string going = to_string(x);
      if (!mp_horizontal[going].size()) return -1;
      if (!sorted_hori[going]) {sort(mp_horizontal[going].begin(),mp_horizontal[going].end());sorted_hori[going] = true;}
      long long le = 0, ri = mp_horizontal[going].size()-1;
      while(le<ri-1){
        long long mid = (le+ri)/2;
        if (mp_horizontal[going][mid]>=y) ri = mid;
        else le = mid;
      }
      if (mp_horizontal[going][ri]< y && !between_y(mp_horizontal[going][ri],y,going)) return mp_horizontal[going][ri];
      if (mp_horizontal[going][le]<y  && !between_y(mp_horizontal[going][le],y,going)) return mp_horizontal[going][le];
      return -1;
    }//往下
    long long find_left(long long x, long long y){
      string going = to_string(y);
      if (!mp_vertical[going].size()) return -1;
      if (!sorted_vert[going]) {sort(mp_vertical[going].begin(),mp_vertical[going].end());sorted_vert[going] = true;}
      long long le = 0, ri = mp_vertical[going].size()-1;
      while(le<ri-1){
        long long mid = (le+ri)/2;
        if (mp_vertical[going][mid]>=x) ri = mid;
        else le = mid;
      }
      if (mp_vertical[going][ri]<x && !between_x(x,mp_vertical[going][ri],going)) return mp_vertical[going][ri];
      if (mp_vertical[going][le]<x && !between_x(x,mp_vertical[going][le],going)) return mp_vertical[going][le];
      return -1;
    }//往左
    long long find_right(long long x, long long y){
      string going = to_string(y);
      if (!mp_vertical[going].size()) return -1;
      if (!sorted_vert[going]) {sort(mp_vertical[going].begin(),mp_vertical[going].end());sorted_vert[going] = true;}
      long long le = 0, ri = mp_vertical[going].size()-1;
      while(le<ri-1){
        long long mid = (le+ri)/2;
        if (mp_vertical[going][mid]<=x) le = mid;
        else ri = mid;
      }
      if (mp_vertical[going][le]>x && !between_x(x,mp_vertical[going][le],going)) return mp_vertical[going][le];
      if (mp_vertical[going][ri]>x && !between_x(x,mp_vertical[going][ri],going)) return mp_vertical[going][ri];
      return -1;
    }//往右
    void find_all(int x ,int y){
      cout << find_up(x,y) << " " << find_down(x,y) << " " << find_left(x,y) << " " << find_right(x,y) << endl;
    }//这是我自己用来测试的程序
    int main(){
      scanf("%lld%lld%lld%lld%lld",&n,&sx,&sy,&ex,&ey);
      sx+=1e9;sy+=1e9;ex+=1e9;ey+=1e9;
      for (long long i=0;i<n;i++){
        long long a,b;scanf("%lld%lld",&a,&b);
        a+=1e9;b+=1e9;
        stone_x[to_string(a)].push_back(b);
        stone_y[to_string(b)].push_back(a);//将石头的状态分别计入map中
        if (a-1>=0) mp_vertical[to_string(b)].push_back(a-1);
        mp_vertical[to_string(b)].push_back(a+1);vec_x.push_back(a+1);
        if (b-1>=0) mp_horizontal[to_string(a)].push_back(b-1);
        mp_horizontal[to_string(a)].push_back(b+1);
        //建立虚拟节点(其实a-1这些不要都无所谓了)
      }
      queue<pp> q;
      q.push(make_pair(sx,sy));
      vis[to_string(sx)+"?"+to_string(sy)] = 0;
      while(!q.empty()){
        long long qf = q.front().f, qs = q.front().s; q.pop();
        long long prev = vis[to_string(qf)+"?"+to_string(qs)];
        if (qf==ex && qs==ey) {cout << prev;return 0;}
        long long le = find_left(qf,qs), ri = find_right(qf,qs), up = find_up(qf,qs), down = find_down(qf,qs);
        if (le!=-1){
          if (!vis[to_string(le)+"?"+to_string(qs)] && (le!=sx || qs!=sy)){
            vis[to_string(le)+"?"+to_string(qs)] = prev+1;
            q.push(make_pair(le,qs));
          }//能往左并且左边的点没拿过
        }
        if (ri!=-1){
          if (!vis[to_string(ri)+"?"+to_string(qs)] && (ri!=sx || qs!=sy)){
            vis[to_string(ri)+"?"+to_string(qs)] = prev+1;
            q.push(make_pair(ri,qs));
          }//能往右并且右边的点没拿过
        }
        if (up!=-1){
          if (!vis[to_string(qf)+"?"+to_string(up)] && (qf!=sx || up!=sy)){
            vis[to_string(qf)+"?"+to_string(up)] = prev+1;
            q.push(make_pair(qf,up));
          }//能往上并且上边的点没拿过
        }
        if (down!=-1){
          if (!vis[to_string(qf)+"?"+to_string(down)] && (qf!=sx || down!=sy)){
            vis[to_string(qf)+"?"+to_string(down)] = prev+1;
            q.push(make_pair(qf,down));
          }//能往下并且下面的点没拿过
        }
      }
    }
    

    其实这个代码意义不算很大(毕竟确实又臭又长).这就是一个参考,如果会用set建议使用楼上的方法.

    顺便留下一组毒瘤数据造福后人

    /*
    9
    0 0 -2 -3
    -3 0
    -2 -2
    -3 -3
    -1 -3
    -1 -4
    -2 -4
    -3 -4
    -2 -5
    0 -3*/
    

    p.s这组数据无解(虽然原题不会出现,但可以测试一下)

  • 相关阅读:
    LNMP安装后MYSQL数据库无法远程访问解决
    Ubuntu忘记root密码怎么办?
    composer安装出现proc_open没有开启问题的解决方案
    LNMP搭建环境遇到的N多坑
    lnmp HTTP ERROR 500
    LNMP集成运行(开发)环境的部署
    最新javamail 使用方案,可以异步发送邮件
    vi常用快捷键
    Dom4j解析XML文件
    Multiple markers at this line @Override的解决方法
  • 原文地址:https://www.cnblogs.com/DannyXu/p/12289660.html
Copyright © 2011-2022 走看看