題意簡述:平面上給定
開始做的時候只想到了一個
性質1:存在一組解橫座標單調不減(因爲建築都在起點的右側)。
性質2:每個建築可以看成建築左側的擋板,因爲每個矩形周圍區域不會有別的矩形,所以若能貼着擋板左邊走到的地方一定能在原圖中走到。
所以有一種解法是在每條邊的兩個端點外側放置兩個點,每個點向左邊第一個碰到的擋板連邊,邊數和點數一個級別,但由於是網格圖,一開始寫的SPFA硬生生被卡T。
#include<bits/stdc++.h>
#define y1 HA
const int D = 1e6 + 10;
const int A = 2e6 + 30;
const int N = 2e5 + 50;
const int INF = 4e6;
struct P{
int x, y;
P(){}
P(int _x, int _y):
x(_x),y(_y){}
}p[N];
struct L{
int x, y1, y2;
}a[N/2];
struct edge{
int y, v, next;
}mp[N*2];
int x,y,n,cnt,s,first[N],lc[A*2],rc[A*2],tag[A*2],q[N+10],dis[N];
bool inq[N];
bool cmp(const L &a, const L &b){
return a.x < b.x;
}
void build(int i, int l, int r){
if (l == r) return;
tag[i] = -1;
build(lc[i] = ++cnt,l,(l+r)/2);
build(rc[i] = ++cnt,(l+r)/2+1,r);
}
void pushdown(int i){
if (tag[i] == -1) return;
tag[lc[i]] = tag[rc[i]] = tag[i];
tag[i] = -1;
}
void chg(int i, int l, int r, int _l, int _r, int c){
if (l > _r || r < _l) return;
if (l >= _l && r <= _r) {tag[i] = c; return;}
pushdown(i);
chg(lc[i],l,(l+r)/2,_l,_r,c);
chg(rc[i],(l+r)/2+1,r,_l,_r,c);
}
int qry(int i, int l, int r, int pos){
if (l == r) return tag[i];
pushdown(i);
if (pos <= (l+r)/2) return qry(lc[i],l,(l+r)/2,pos);
return qry(rc[i],(l+r)/2+1,r,pos);
}
int d(int u, int v){
return abs(p[u].x - p[v].x) + abs(p[u].y - p[v].y);
}
void ins(int x, int y, int v){
mp[++s] = (edge){y,v,first[x]};
first[x] = s;
}
struct rec{
int x,d;
}heap[N*2],top;
void push(const rec &c){
heap[++cnt] = c;
int x = cnt;
while (x > 1 && heap[x].d < heap[x>>1].d)
std::swap(heap[x],heap[x>>1]),
x >>= 1;
};
rec poop(){
rec ret = heap[1];
heap[1] = heap[cnt--];
int x = 1;
while (x*2<=cnt && heap[x*2].d<heap[x].d || x*2+1<=cnt && heap[x*2+1].d<heap[x].d){
int e = x * 2 + (x*2+1<=cnt && heap[x*2+1].d<heap[x*2].d);
std::swap(heap[x],heap[e]);
x = e;
}
return ret;
}
void Dijkstra(){
n = (n + 1) * 2; cnt = 0;
for (int i=2; i<=n; i++) dis[i] = INF;
for (int t=first[1]; t; t=mp[t].next)
dis[mp[t].y] = mp[t].v,
push((rec){mp[t].y,dis[mp[t].y]});
while (cnt){
for (top = poop(); cnt && dis[top.x] != top.d;top = poop());
for (int t=first[top.x]; t; t=mp[t].next)
if (dis[top.x] + mp[t].v < dis[mp[t].y])
dis[mp[t].y] = dis[top.x] + mp[t].v,
push((rec){mp[t].y,dis[mp[t].y]});
}
}
int main(){
scanf("%d%d%d",&x,&y,&n);
p[1] = P(0,D);
p[(n+1)*2] = P(x,y+D);
for (int i=1; i<=n; i++)
scanf("%d%d%d%d",&a[i].x,&a[i].y1,&x,&a[i].y2),
a[i].y1 += D, a[i].y2 += D;
std::sort(a+1,a+n+1,cmp);
for (int i=1; i<=n; i++)
p[i*2 ] = P(a[i].x,a[i].y1-1),
p[i*2+1] = P(a[i].x,a[i].y2+1);
build(cnt = 1,1,A);
for (int i=2; i<=(n+1)*2; i++){
if (p[i].x >= p[(n+1)*2].x) i = (n+1)*2;
int q = qry(1,1,A,p[i].y);
ins(q*2+1,i,d(q*2+1,i));
if (q) ins(q*2,i,d(q*2,i));
if (i & 1) chg(1,1,A,a[i>>1].y1,a[i>>1].y2,i>>1);
}
Dijkstra();
printf("%d\n",dis[n]);
return 0;
}
附上醜陋暴力和醜陋的判斷是否能連邊
#include<bits/stdc++.h>
#define y1 HA
const int N = 4050;
const int INF = 4e6;
struct abc{
struct P{
int x, y;
P(){}
P(int _x, int _y):
x(_x),y(_y){}
}a[N];
struct edge{
int y,v,next;
}mp[N*N];
int n,x,y,cnt,S,T,dis[N],q[N+10],x1[N],x2[N],y1[N],y2[N],first[N],s;
bool inq[N];
};
struct P{
int x, y;
P(){}
P(int _x, int _y):
x(_x),y(_y){}
}a[N];
struct edge{
int y,v,next;
}mp[N*N];
int n,x,y,cnt,S,T,dis[N],q[N+10],x1[N],x2[N],y1[N],y2[N],first[N],s;
bool inq[N];
bool range(int a, int x, int y){
return (a >= x && a <= y) || (a >= y && a <= x);
}
void ins(int x, int y, int v){
mp[++s] = (edge){y,v,first[x]}; first[x] = s;
mp[++s] = (edge){x,v,first[y]}; first[y] = s;
}
void SPFA(){
int head = 1, tail = 2;
for (int i=1; i<=cnt; i++) dis[i] = INF;
inq[q[head] = S] = 1;
dis[S] = 0;
while (head != tail){
int x = q[head];
for (int t=first[x]; t>0; t=mp[t].next)
if (dis[x] + mp[t].v < dis[mp[t].y]){
dis[mp[t].y] = dis[x] + mp[t].v;
if (!inq[mp[t].y]){
inq[q[tail++] = mp[t].y] = 1;
if (tail > N) tail = 1;
}
}
inq[q[head++]] = 0;
if (head > N) head = 1;
}
}
int main(){
//fprintf(stderr,"%.6f\n",sizeof(abc) * 1.0 / 1024 / 1024);
//freopen("B.in","r",stdin);
//freopen("B.out","w",stdout);
a[S = 1] = P(0,0);
scanf("%d%d%d",&x,&y,&n);
a[T = 2] = P(x,y);
cnt = 2;
for (int i=1; i<=n; i++){
scanf("%d%d%d%d",&x1[i],&y1[i],&x2[i],&y2[i]);
if (x1[i] > x2[i]) std::swap(x1[i],x2[i]);
if (y1[i] > y2[i]) std::swap(y1[i],y2[i]);
a[++cnt] = P(x1[i]-1,y1[i]-1);
a[++cnt] = P(x1[i]-1,y2[i]+1);
a[++cnt] = P(x2[i]+1,y1[i]-1);
a[++cnt] = P(x2[i]+1,y2[i]+1);
}
for (int i=1; i<cnt; i++)
for (int j=i+1; j<=cnt; j++){
bool xy = 1, yx = 1;
for (int k=1; k<=n && (xy || yx); k++){
if (xy && ( (range(a[i].x,x1[k],x2[k]) && (range(y1[k],a[i].y,a[j].y) || range(y2[k],a[i].y,a[j].y)))
|| (range(a[j].y,y1[k],y2[k]) && (range(x1[k],a[i].x,a[j].x) || range(x2[k],a[i].x,a[j].x))) )) xy = 0;
if (yx && ( (range(a[j].x,x1[k],x2[k]) && (range(y1[k],a[i].y,a[j].y) || range(y2[k],a[i].y,a[j].y)))
|| (range(a[i].y,y1[k],y2[k]) && (range(x1[k],a[i].x,a[j].x) || range(x2[k],a[i].x,a[j].x))) )) yx = 0;
}
if (xy || yx) ins(i,j,abs(a[i].x-a[j].x) + abs(a[i].y - a[j].y));
}
SPFA();
printf("%d\n",dis[T]);
return 0;
}