题解 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 坐标系内有若干个点,问把这些点都圈起来的最小凸包周长. 这道题就是一道凸包的模板题啊,只要求出凸包后在计算就好了,给出几个注意点 记得检查是否有吧 ...
随机推荐
- JAVA - 创建SpringBoot项目
JAVA - 创建SpringBoot项目 Spring Boot是由Pivotal团队提供的全新框架,设计目的是用来简化新Spring应用的初始搭建以及开发过程.它主要推崇的是'消灭配置’,实现零配 ...
- 第十篇 Form表单
Form表单 阅读目录(Content) Form介绍 普通的登录 使用form组件 Form那些事儿 常用字段演示 校验 使用Django Form流程 补充进阶 应用Bootstrap样式 批量添 ...
- CGridCtrl显示图片
- 如何在Ubuntu 18.04上安装和卸载TeamViewer
卸载命令:sudo apt --purge remove teamviewer 安装:https://www.linuxidc.com/Linux/2018-05/152282.htm 如何在Ubun ...
- k8s常用github网站
1.集群安装地址 https://github.com/gjmzj/kubeasz 采用本网站安装需要注意点: 1.docker的cgroup驱动 需改为cgroupfs 2 .安装完master和n ...
- jquery获取高度
分为以下几种: .height() -获取匹配元素集合中的第一个元素的当前计算高度值 或 设置每一个匹配元素的高度值. -.css('height') 和 .height()之间的区别是后者返回一个没 ...
- 剑指offer_1.24_Day_4
构建乘积数组 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1] ...
- (一)IOC基础推导及理论
环境准备:见java环境搭建,新建maven项目 1.写一个UserDao接口 public interface UserDao { public void getUser(); } 2.再写Dao的 ...
- 数据库连接池DBCP的使用
一.直接使用代码链接(一般企业开发不用这种方式) 1.导入JAR 把jar包拷贝到lib文件夹里面然后右击 build path一下 2.建一个jdbc.proprtties文件 driverClas ...
- PSI-BLAST|PHI-BLAST|UniProt|IGV|Galaxy|clustalx
生物信息学软件: NCBI:BLAST,设定k-mer 默认是全局比对,Blastn是局部比对. PSI-BLAST最灵敏的BLAST,选中部分矩阵后在数据库中查找相应蛋白. PHI-BLAST找氨基 ...