題目
給出一個含有若干個不相交矩形的平面直角座標系,以及起點和終點。
從起點到終點的路途中,不能經過矩形,但是可以在矩形邊經過。
求最短的曼哈頓距離。
正解
比賽時認爲是歐幾里得距離,所以不存在思考……
先說DYP的做法:
對於一個點,找到上下左右第一個碰到的邊界,然後可以形成一個矩形。這個點可以曼哈頓最短距離到達矩形內任意點。
然後每個頂點以及起點終點向周圍連邊,連的是最近碰到的每個邊界的兩個端點。
然後跑最短路。
在說奇妙的正解:
由於這題的矩形都不相交,於是有些很神奇的性質。
以下建議感性理解,不解釋
首先,橫座標和縱座標至少有一個是單調的。
假設橫座標單調,如何判斷?
欽定起點在終點左邊,假如起點在終點上面,從起點開始不停往下走,遇到障礙就往右。
一直走到終點所在的那一列,如果這時候縱座標小於終點,那麼就不單調。
接下來考慮如何計算答案。
假如起點在終點左邊。從起點開始往右掃,遇到障礙就分兩路到障礙的兩邊,並且將橫座標移到障礙這裏。(如果沒有遇到障礙,先暫時保持着橫座標不變,具體原因自己去玩)
一直這麼做下去,直到計算過兩列之間的所有障礙。
剩下的距離就是最短的曼哈頓距離。
無法用精準的語言來說明它的正確性,但它就是很對……
這個東西隨便用set
維護就可以了。
代碼
具體細節在此
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <set>
#define N 200010
int n;
struct DOT{
int x,y;
void swap(){std::swap(x,y);}
} S,T;
struct Sqr{
DOT p,q;
} z[N];
int ans=INT_MAX;
struct Segment{
int x,l,r;
} seg[N*2];
int m;
bool cmp1(Segment a,Segment b){return a.x>b.x;}
bool cmp0(Segment a,Segment b){return a.x<b.x;}
struct Status{
int y;
mutable int x,s;
};
bool operator<(Status a,Status b){return a.y<b.y;}
multiset<Status> s;
bool judge(){
if (S.x>T.x)
swap(S,T);
if (S.y>T.y){
m=0;
for (int i=1;i<=n;++i)
if (S.y>z[i].q.y && z[i].q.y>T.y)
seg[++m]={z[i].q.y,z[i].p.x,z[i].q.x};
sort(seg+1,seg+m+1,cmp1);
}
else{
m=0;
for (int i=1;i<=n;++i)
if (S.y<z[i].p.y && z[i].p.y<T.y)
seg[++m]={z[i].p.y,z[i].p.x,z[i].q.x};
sort(seg+1,seg+m+1,cmp0);
}
int x=S.x;
for (int i=1;i<=m;++i)
if (seg[i].l<x && x<seg[i].r)
x=seg[i].r;
return x<=T.x;
}
void calc(){
if (S.x>T.x)
swap(S,T);
s.clear();
m=0;
for (int i=1;i<=n;++i)
if (S.x<z[i].p.x && z[i].p.x<T.x)
seg[++m]={z[i].p.x,z[i].p.y,z[i].q.y};
sort(seg+1,seg+m+1,cmp0);
s.insert({S.y,S.x,0});
for (int i=1;i<=m;++i){
int x=seg[i].x,l=seg[i].l,r=seg[i].r;
set<Status>::iterator p=s.lower_bound({l}),u,v;
bool appear=0;
for (auto q=p;p!=s.end() && l<p->y && p->y<r;q=p,++p,s.erase(q)){
if (appear==0){
appear=1;
//s.insert() return pair<...,bool>
u=s.insert((Status){r,x,p->s+(x-p->x)+abs(p->y-r)})/*.first*/;
v=s.insert((Status){l,x,p->s+(x-p->x)+abs(p->y-l)})/*.first*/;
}
else{
u->s=min(u->s,p->s+(x-p->x)+abs(p->y-r));
v->s=min(v->s,p->s+(x-p->x)+abs(p->y-l));
}
}
}
for (auto p=s.begin();p!=s.end();++p)
ans=min(ans,p->s+(T.x-p->x)+abs(p->y-T.y));
}
int main(){
// freopen("in.txt","r",stdin);
freopen("travel.in","r",stdin);
freopen("travel.out","w",stdout);
scanf("%d%d%d%d%d",&n,&S.x,&S.y,&T.x,&T.y);
for (int i=1;i<=n;++i)
scanf("%d%d%d%d",&z[i].p.x,&z[i].p.y,&z[i].q.x,&z[i].q.y);
if (judge())
calc();
S.swap(),T.swap();
for (int i=1;i<=n;++i)
z[i].p.swap(),z[i].q.swap();
if (judge())
calc();
printf("%d\n",ans);
return 0;
}
總結
還是不要總想着數據結構……
有些問題性質很優美的……