题解 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这组数据无解(虽然原题不会出现,但可以测试一下)
题解 P2981 【[USACO10FEB]奶牛在冰Cows on Ice】的更多相关文章
- luogu P2742 【模板】二维凸包 / [USACO5.1]圈奶牛Fencing the Cows
题解: 二维凸包裸题 按照x坐标为第一关键字,y坐标为第二关键字排序 然后相邻判断叉积用单调队列搞过去 正反都做一次就好了 代码: #include <bits/stdc++.h> usi ...
- LG2742 【模板】二维凸包 / [USACO5.1]圈奶牛Fencing the Cows
题意 题目描述 农夫约翰想要建造一个围栏用来围住他的奶牛,可是他资金匮乏.他建造的围栏必须包括他的奶牛喜欢吃草的所有地点.对于给出的这些地点的坐标,计算最短的能够围住这些点的围栏的长度. 输入输出格式 ...
- 题解 p2017 [USACO09DEC]晕牛Dizzy Cows
前言:P大终于又更新了 正文 转送门 由于当时我这个ZZ不知怎么了,这份题解排版可能有些尴尬,建议大家读完题后,看我主程序前的代码的注释,然后看最下面的图片,然后看第一张图片,对不起,望多谅解 以样例 ...
- [洛谷P2742]【模板】二维凸包([USACO5.1]圈奶牛Fencing the Cows)
题目大意:求一个点集凸包边长 题解:求凸包,直接求 卡点:发现在较后面数位上有较小的误差,还以为是浮点数误差,最后发现是构造函数写成了$int$类型 C++ Code: #include <al ...
- 洛谷 P2742 [USACO5.1]圈奶牛Fencing the Cows
题目描述 农夫约翰想要建造一个围栏用来围住他的奶牛,可是他资金匮乏.他建造的围栏必须包括他的奶牛喜欢吃草的所有地点.对于给出的这些地点的坐标,计算最短的能够围住这些点的围栏的长度. 输入输出格式 输入 ...
- P2742 [USACO5.1]圈奶牛Fencing the Cows
题目描述 农夫约翰想要建造一个围栏用来围住他的奶牛,可是他资金匮乏.他建造的围栏必须包括他的奶牛喜欢吃草的所有地点.对于给出的这些地点的坐标,计算最短的能够围住这些点的围栏的长度. 输入输出格式 输入 ...
- 洛谷 题解 P1842 【奶牛玩杂技】
本蒟蒻又双叒叕被爆踩辣! Solution: 我们先看数据,50000,那么O(n)或者O(n log(n))是可以过的,非严格O(n * sqrt(n))要卡卡常,说不定也可以过. 那么什么算法可以 ...
- 题解 [USACO Mar08] 奶牛跑步
[USACO Mar08] 奶牛跑步 Description Bessie准备用从牛棚跑到池塘的方法来锻炼. 但是因为她懒,她只准备沿着下坡的路跑到池塘,然后走回牛棚. Bessie也不想跑得太远,所 ...
- 【模板】二维凸包 / [USACO5.1]圈奶牛Fencing the Cows
Problem surface 戳我 Meaning 坐标系内有若干个点,问把这些点都圈起来的最小凸包周长. 这道题就是一道凸包的模板题啊,只要求出凸包后在计算就好了,给出几个注意点 记得检查是否有吧 ...
随机推荐
- Spark调优(一)
一.对多次使用的RDD进行持久化 如何选择一种最合适的持久化策略? 默认情况下,性能最高的当然是MEMORY_ONLY,但前提是你的内存必须足够足够大, 可以绰绰有余地存放下整个RDD的所有数据.因为 ...
- 六、React 键盘事件 表单事件 事件对象以及React中的ref获取dom节点 、React实现类似Vue的双向数据绑定
接:https://www.cnblogs.com/chenxi188/p/11782349.html 事件对象 .键盘事件. 表单事件 .ref获取dom节点.React实现类似vue双向数据绑定 ...
- MERGE INTO:存在就更新不存在就新增——oracle
MERGE INTO [your table-name] [rename your table here] USING ( [write your query here] )[rename your ...
- c# 占位符 {0} {1}
占位符就是先占住一个固定的位置,等着你再往里面添加内容的符号.站位符由{数字}组成,数字由0开始编号. 第1个占位符:{0} 第2个占位符:{1} 第2个占位符:{2} 初学C#之变量.占位符.转义符 ...
- 08 SSM整合案例(企业权限管理系统):10.权限关联与控制
04.AdminLTE的基本介绍 05.SSM整合案例的基本介绍 06.产品操作 07.订单操作 08.权限控制 09.用户操作 10.权限关联与控制 11.AOP日志 10.权限关联与控制 1.用户 ...
- Kicstart+pxe搭建自动化安装Linux 整理了一下
一直想把 有道云得笔记整理一下传上来 都是自己亲测过 ,先来这篇吧 : 二小时安装 100台Linux system 其实Winddows 也可以这样搞 只是方法 组件不同 原理一样 ...
- 九、CI框架之将URI转为数组原型
一.输入以下代码,uri_to_assoc的参数默认从3开始 二.输出效果如下: 不忘初心,如果您认为这篇文章有价值,认同作者的付出,可以微信二维码打赏任意金额给作者(微信号:382477247)哦, ...
- GIT-Linux(CentOS7)系统安装Git
GIT-Linux(CentOS7)系统安装Git 未成功 查看是否已安装了Git 发现Git版本已存在,说明已安装了Git [root@localhost ~]# rpm -qa|grep git ...
- HDU——Monkey and Banana 动态规划
Monkey and Banana Time Limit:2000 ...
- 二分+半平面交——poj1279
/* 二分距离,凸包所有边往左平移这个距离,半平面交后看是否还有核存在 */ #include<iostream> #include<cstring> #include< ...