传送门
题目大意:在二维平面上有起点和终点,若干不相交、边界平行或竖直的矩形。不能进入矩形内部,只能在矩形的边界上改变方向,求起点到终点的最短距离或者No Path。
这题和之前写过的冰原探险那道题挺像的,都是将这种图连边然后跑最短路
因为最优情况下只会在矩形的顶点处改变方向,所以可以先将坐标离散化,然后对于矩形的每一个顶点向第一个能到达的地方连边
这样的话除了矩形的顶点图上还会多出来一些有效的点,对于所有的有效点向其四个方向最近的点连边,然后跑最短路就行了
刚开始的时候计算上限的时候算错了。。刚开始以为有点数和边数都是 O(n2) 级别的,因为两两枚举。实际上这样计算是错的,因为从一个矩形出发至多只会搞出来12个新的有效点,并且每个点都至多会连出去4条边,所以点数和边数实际上都是 O(n) 级别的,这样就没问题了
注意特判:1、起点和终点在矩形里的情况2、矩形互相包含的情况(虽然ATP贴心的数据生成器都把这些恶心情况判掉了
#include
#include
#include
#include
#include
#include
using namespace std;
int T,n,xs,ys,xt,yt,xx,yy,s,t,cnt;long long inf;
int a[1005],b[1005],c[1005],d[1005],X[2005],Y[2005],squ[2005][2005],pt[2005][2005];
int tot,point[24005],nxt[200005],v[200005];long long l[200005];
long long dis[24005];bool vis[24005],flag[2005];
struct data{int x,y,id;}p[24005];
queue <int> q;
void clear()
{
n=xs=ys=xt=yt=xx=yy=s=t=cnt=tot=0;inf=0;
memset(a,0,sizeof(a));memset(b,0,sizeof(b));memset(c,0,sizeof(c));memset(d,0,sizeof(d));
memset(X,0,sizeof(X));memset(Y,0,sizeof(Y));memset(squ,0,sizeof(squ));memset(pt,0,sizeof(pt));
memset(point,0,sizeof(point));memset(nxt,0,sizeof(nxt));memset(v,0,sizeof(v));
memset(l,0,sizeof(l));memset(dis,0,sizeof(dis));memset(vis,0,sizeof(vis));
}
void walk(int x,int y,int dx,int dy)
{
x+=dx,y+=dy;
while (!squ[x][y])
{
if (x<1||x>xx||y<1||y>yy) return;
x+=dx,y+=dy;
}
pt[x][y]=1;
}
int cmpx(data a,data b){return a.xint cmpy(data a,data b){return a.ylong long Abs(long long x){return (x>0)?x:-x;}
long long Dis(data a,data b){return Abs(X[a.x]-X[b.x])+Abs(Y[a.y]-Y[b.y]);}
void add(int x,int y,long long z)
{
if (x==y) return;
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; l[tot]=z;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; l[tot]=z;
}
void spfa()
{
memset(dis,127,sizeof(dis));inf=dis[0];
dis[s]=0;vis[s]=1;q.push(s);
while (!q.empty())
{
int now=q.front();q.pop();
vis[now]=0;
for (int i=point[now];i;i=nxt[i])
if (dis[v[i]]>dis[now]+l[i])
{
dis[v[i]]=dis[now]+l[i];
if (!vis[v[i]]) vis[v[i]]=1,q.push(v[i]);
}
}
}
int main()
{
scanf("%d",&T);
while (T--)
{
clear();
scanf("%d%d%d%d",&xs,&ys,&xt,&yt);
X[++xx]=xs,X[++xx]=xt,Y[++yy]=ys,Y[++yy]=yt;
scanf("%d",&n);
for (int i=1;i<=n;++i)
{
scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
if (a[i]>c[i]) swap(a[i],c[i]);
if (b[i]>d[i]) swap(b[i],d[i]);
X[++xx]=a[i],X[++xx]=c[i],Y[++yy]=b[i],Y[++yy]=d[i];
}
sort(X+1,X+xx+1);xx=unique(X+1,X+xx+1)-X-1;
sort(Y+1,Y+yy+1);yy=unique(Y+1,Y+yy+1)-Y-1;
xs=lower_bound(X+1,X+xx+1,xs)-X;xt=lower_bound(X+1,X+xx+1,xt)-X;
ys=lower_bound(Y+1,Y+yy+1,ys)-Y;yt=lower_bound(Y+1,Y+yy+1,yt)-Y;
squ[xs][ys]=squ[xt][yt]=-1;
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
if (i!=j&&a[i]>=a[j]&&b[i]>=b[j]&&c[i]<=c[j]&&d[i]<=d[j])
{
flag[i]=1;
break;
}
for (int i=1;i<=n;++i)
{
if (flag[i]) continue;
a[i]=lower_bound(X+1,X+xx+1,a[i])-X;
c[i]=lower_bound(X+1,X+xx+1,c[i])-X;
b[i]=lower_bound(Y+1,Y+yy+1,b[i])-Y;
d[i]=lower_bound(Y+1,Y+yy+1,d[i])-Y;
for (int j=a[i];j<=c[i];++j) squ[j][b[i]]=1,squ[j][d[i]]=2;
for (int j=b[i];j<=d[i];++j) squ[a[i]][j]=1,squ[c[i]][j]=2;
squ[a[i]][b[i]]=squ[a[i]][d[i]]=squ[c[i]][b[i]]=squ[c[i]][d[i]]=-1;
}
for (int i=1;i<=n;++i)
{
if (xs>a[i]&&ys>b[i]&&xsputs("No Path");
return 0;
}
if (xt>a[i]&&yt>b[i]&&xtputs("No Path");
return 0;
}
}
for (int i=1;i<=n;++i)
{
if (flag[i]) continue;
walk(a[i],b[i],-1,0);walk(a[i],b[i],0,-1);walk(a[i],d[i],-1,0);walk(a[i],d[i],0,1);
walk(c[i],b[i],1,0);walk(c[i],b[i],0,-1);walk(c[i],d[i],1,0);walk(c[i],d[i],0,1);
pt[a[i]][b[i]]=pt[a[i]][d[i]]=pt[c[i]][b[i]]=pt[c[i]][d[i]]=1;
}pt[xs][ys]=pt[xt][yt]=1;
walk(xs,ys,-1,0);walk(xs,ys,1,0);walk(xs,ys,0,-1);walk(xs,ys,0,1);
walk(xt,yt,-1,0);walk(xt,yt,1,0);walk(xt,yt,0,-1);walk(xt,yt,0,1);
for (int i=1;i<=xx;++i)
for (int j=1;j<=yy;++j)
if (pt[i][j])
{
p[++cnt].x=i,p[cnt].y=j,p[cnt].id=cnt;
if (i==xs&&j==ys) s=cnt;
if (i==xt&&j==yt) t=cnt;
}
sort(p+1,p+cnt+1,cmpx);
for (int i=1,j;i<=cnt;i=j)
{
j=i+1;
while (j<=cnt&&p[j].x==p[i].x)
{
if (squ[p[j-1].x][p[j-1].y]==-1||squ[p[j].x][p[j].y]==-1
||squ[p[j-1].x][p[j-1].y]>=squ[p[j].x][p[j].y])
add(p[j-1].id,p[j].id,Dis(p[j-1],p[j]));
++j;
}
}
sort(p+1,p+cnt+1,cmpy);
for (int i=1,j;i<=cnt;i=j)
{
j=i+1;
while (j<=cnt&&p[j].y==p[i].y)
{
if (squ[p[j-1].x][p[j-1].y]==-1||squ[p[j].x][p[j].y]==-1
||squ[p[j-1].x][p[j-1].y]>=squ[p[j].x][p[j].y])
add(p[j-1].id,p[j].id,Dis(p[j-1],p[j]));
++j;
}
}
spfa();
if (dis[t]!=inf) printf("%lld\n",dis[t]);
else puts("No Path");
}
}
再次感谢ATP的数据生成器!!!
#include
#include
#include
#include
#include
#include
#define random(x)(rand()*rand()%x+1)
#define N 10000
using namespace std;
int n,m1,m2,X[10010],Y[10010],Xx[10010],Yy[10010];
bool ext[10010][10010];
bool Ins(int x,int y,int xx,int yy,int i){
if (x>=X[i]&&x<=Xx[i]&&y>=Y[i]&&y<=Yy[i]) return true;
if (x>Xx[i]||xxreturn false;
if (y>Yy[i]||yyreturn false;
if (xxX[i]&&yyY[i]) return false;
return true;
}
bool In(int x,int y){
for (int i=1;i<=n;i++)
if (x>X[i]&&xY[i]&&yreturn true;
return false;
}
int main()
{
freopen("input.txt","w",stdout);
srand(time(0));
int T=10;
printf("%d\n",T);
while (T--)
{
n=1000;m1=1;m2=1;
memset(ext,false,sizeof(ext));
for (int i=1;i<=n;){
int x,y,xx,yy;
bool flag=false;
x=random(N);y=random(N);
xx=random(N);yy=random(N);
if (x>xx) swap(x,xx);
if (y>yy) swap(y,yy);
if (x==xx||y==yy) continue;
for (int j=1;j<=i;j++)
if (Ins(x,y,xx,yy,j)){
flag=true;break;
}
if (flag==true) continue;
X[i]=x;Y[i]=y;Xx[i]=xx;Yy[i]=yy;++i;
}
for (int i=1;i<=m1;i++){
int x=random(N),y=random(N);
while (ext[x][y]==true||In(x,y)){
x=random(N);y=random(N);
}
ext[x][y]=true;
printf("%d %d ",x,y);
}
for (int i=1;i<=m2;i++){
int x=random(N),y=random(N);
while (ext[x][y]==true||In(x,y)){
x=random(N);y=random(N);
}
ext[x][y]=true;
printf("%d %d\n",x,y);
}
printf("%d\n",n);
for (int i=1;i<=n;i++)
printf("%d %d %d %d\n",X[i],Y[i],Xx[i],Yy[i]);
}
return 0;
}