标签:建议 set swa 另一个 front 虚拟 状态 order class
楼上的思路都是从一个石头找跳到另一个石头的路径,但其实这题可以对于上下左右四个方向分别做一个虚拟节点,然后只需要找虚拟节点左边的虚拟节点就行了
问题是:不会用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】
标签:建议 set swa 另一个 front 虚拟 状态 order class
原文地址:https://www.cnblogs.com/DannyXu/p/12289660.html