题解 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 坐标系内有若干个点,问把这些点都圈起来的最小凸包周长. 这道题就是一道凸包的模板题啊,只要求出凸包后在计算就好了,给出几个注意点 记得检查是否有吧 ...
随机推荐
- Node.js 介绍
章节 Node.js 介绍 Node.js 入门 Node.js 模块 Node.js HTTP模块 Node.js 文件系统模块 Node.js URL模块 Node.js NPM Node.js ...
- Centos 7 x86_64 环境Python2.7升级Python3.7.4
升级Python3.7.4 #安装补丁包yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel read ...
- Profiling Top Kagglers: Bestfitting, Currently #1 in the World
We have a new #1 on our leaderboard – a competitor who surprisingly joined the platform just two yea ...
- Dynamics CRM - 解决无法使用 Ribbon Workbench 2016 定制 Sub-Grid View Button 的问题(SubGrid MainTab 消失之谜)
发现问题: 在 Dynamics CRM 开发中,会经常使用 Ribbon Workbench 工具来定制 Button 或者对已有 Button 进行自定义功能开发,比如隐藏 SubGrid 的 A ...
- Spring Boot2(001):入门介绍和一些官网链接参考
Spring官方文档比较齐全,学习的过程中可以多参考官方文档,最权威的版本.01.Spring Boot的一些官方链接 01.01 Spring Boot官网 https://spring.io/pr ...
- 十五、CI框架之自动加载数据库
一.在config的autoload.php文件中,如果写入以下代码,那么在控制器中无需再次加载数据库了,相当于全局自动加载数据库了 不忘初心,如果您认为这篇文章有价值,认同作者的付出,可以微信二维码 ...
- 四、CI框架之通过URL路径访问C中的函数
一.在C中写一个test001函数 二.在路径http://127.0.0.1/CodeIgniter-3.1.10/index.php/welcome/test001中访问 不忘初心,如果您认为这篇 ...
- 实验吧Web-中-登陆一下好吗??
题目上说:不要怀疑,我已经过滤了一切,还再逼你注入,哈哈哈哈哈! 可以试试,只要是输入的关键字都被过滤了,双写也被过滤掉了. 用万能密码发现,or被过滤掉了. 这里用到的是admin为:'=',密码为 ...
- 把a表格的内容读取出来,然后写到b表格
把a表格的内容读取出来,然后写到b表格 #!/usr/bin/env python3 import sys #控制台要输入的两个参数格式为:python script_name.py 参数1 参数2 ...
- java里mongodb复合查询
Query query = new Query();Criteria criteria = Criteria.where("packetTitle").is(redPacketSt ...