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

问题是:不会用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这组数据无解(虽然原题不会出现,但可以测试一下)

题解 P2981 【[USACO10FEB]奶牛在冰Cows on Ice】的更多相关文章

  1. luogu P2742 【模板】二维凸包 / [USACO5.1]圈奶牛Fencing the Cows

    题解: 二维凸包裸题 按照x坐标为第一关键字,y坐标为第二关键字排序 然后相邻判断叉积用单调队列搞过去 正反都做一次就好了 代码: #include <bits/stdc++.h> usi ...

  2. LG2742 【模板】二维凸包 / [USACO5.1]圈奶牛Fencing the Cows

    题意 题目描述 农夫约翰想要建造一个围栏用来围住他的奶牛,可是他资金匮乏.他建造的围栏必须包括他的奶牛喜欢吃草的所有地点.对于给出的这些地点的坐标,计算最短的能够围住这些点的围栏的长度. 输入输出格式 ...

  3. 题解 p2017 [USACO09DEC]晕牛Dizzy Cows

    前言:P大终于又更新了 正文 转送门 由于当时我这个ZZ不知怎么了,这份题解排版可能有些尴尬,建议大家读完题后,看我主程序前的代码的注释,然后看最下面的图片,然后看第一张图片,对不起,望多谅解 以样例 ...

  4. [洛谷P2742]【模板】二维凸包([USACO5.1]圈奶牛Fencing the Cows)

    题目大意:求一个点集凸包边长 题解:求凸包,直接求 卡点:发现在较后面数位上有较小的误差,还以为是浮点数误差,最后发现是构造函数写成了$int$类型 C++ Code: #include <al ...

  5. 洛谷 P2742 [USACO5.1]圈奶牛Fencing the Cows

    题目描述 农夫约翰想要建造一个围栏用来围住他的奶牛,可是他资金匮乏.他建造的围栏必须包括他的奶牛喜欢吃草的所有地点.对于给出的这些地点的坐标,计算最短的能够围住这些点的围栏的长度. 输入输出格式 输入 ...

  6. P2742 [USACO5.1]圈奶牛Fencing the Cows

    题目描述 农夫约翰想要建造一个围栏用来围住他的奶牛,可是他资金匮乏.他建造的围栏必须包括他的奶牛喜欢吃草的所有地点.对于给出的这些地点的坐标,计算最短的能够围住这些点的围栏的长度. 输入输出格式 输入 ...

  7. 洛谷 题解 P1842 【奶牛玩杂技】

    本蒟蒻又双叒叕被爆踩辣! Solution: 我们先看数据,50000,那么O(n)或者O(n log(n))是可以过的,非严格O(n * sqrt(n))要卡卡常,说不定也可以过. 那么什么算法可以 ...

  8. 题解 [USACO Mar08] 奶牛跑步

    [USACO Mar08] 奶牛跑步 Description Bessie准备用从牛棚跑到池塘的方法来锻炼. 但是因为她懒,她只准备沿着下坡的路跑到池塘,然后走回牛棚. Bessie也不想跑得太远,所 ...

  9. 【模板】二维凸包 / [USACO5.1]圈奶牛Fencing the Cows

    Problem surface 戳我 Meaning 坐标系内有若干个点,问把这些点都圈起来的最小凸包周长. 这道题就是一道凸包的模板题啊,只要求出凸包后在计算就好了,给出几个注意点 记得检查是否有吧 ...

随机推荐

  1. flink笔记(三) flink架构及运行方式

    架构图 Job Managers, Task Managers, Clients JobManager(Master) 用于协调分布式执行.它们用来调度task,协调检查点,协调失败时恢复等. Fli ...

  2. CF1209B Koala and Lights

    It is a holiday season, and Koala is decorating his house with cool lights! He owns n lights, all of ...

  3. 编程入门-Eclipse基本使用

    编程入门-Eclipse基本使用 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.设置Eclipse的基本参数 1>.修改Eclipse默认的文件编码为"utf- ...

  4. NVIDIA TX2--3--NVIDIA Jetson TX2 查看系统版本参数状态及重要指令

    NVIDIA Jetson TX2 查看系统参数状态. 当前博主的TX2更新的版本为:Jetpack 3.3, cuda 9.0.252, cudnn7.0, opencv3.3.1, TensorR ...

  5. DispatcherServlet (1)

    阅读DispatcherServlet源码和<Spring解密>第二十三章 总结 之前对SpringMVC处理请求模糊不清,本周阅读了DispatcherServlet源码,对这一部分有了 ...

  6. 体验京东云 Serverless+AI 人脸属性识别

    云原生计算基金会CNCF(Cloud Native Computing Foundation, CNCF)Serverless Whitepaper v1.0对无服务器计算作了如下定义: Server ...

  7. SQL字符替换函数translater, replace

    translate() 函数原型是:translate(string, from, to) SELECT TRANSLATE('12345', '134', 'ax') 得到:a2x5 这个函数会把f ...

  8. Tmux和一点nohup

    1.当我们用ssh连接服务器时,只有一个终端,但有时候我们希望有多个. 2.有些程序需要运行一些时间,在这个时间里,我们希望可以去做其他的事情. 3.有的程序要跑好几个小时,这时候,我们希望断开远程连 ...

  9. zabbix获取到的数值大于1000之后自动转换成1k

    问题:zabbix在取到的值很大时会自动变成K,M,G 解决方法: 1.修改/var/www/html/zabbix/include/func.inc.php文件(这个文件不一定在这,自己find找下 ...

  10. CF #610Div2 B2.K for the Price of One (Hard Version) (dp解法 && 贪心解法)

    原题链接:http://codeforces.com/contest/1282/problem/B2题目大意:刚开始有 p 块钱,商店有 n 件物品,你每次可以只买一件付那一件的钱,也可以买 k 件只 ...