HDU 4444 Walk (离散化建图+BFS+记忆化搜索) 绝对经典

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4444

题意:给你一些n个矩形,给你一个起点,一个终点,要你求从起点到终点最少需要转多少个弯

题解:因为矩形数量很少50个,可以离散化成102*102的坐标,但是人可以贴着墙壁走,但不能穿过墙壁

所以每个点要分成9等分。建筑物的边占1/3,但是这样有漏洞。

1、当两个墙壁贴在一起,中间还可以过,所以要填补中间

2、当两个矩形的角重合,中间也可以过,要填补中间,但是只能填补中间一个点,不能填补全部的9个点。

还有一点要注意的是,起点有多个,终点也有多个,从任意一起点到任意一终点即可,因为有一些特殊数据,我的例子里面有

图建好了,直接BFS记忆化搜索即可。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <list>
#include <deque>
#include <queue>
#include <iterator>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <cctype>
#include <sstream>
using namespace std; typedef long long LL;
const int N=410;
const LL II=100000000;
const int INF=0x3f3f3f3f;
const int M=12345678;
const double PI=acos(-1.0); int sx,sy,ex,ey;
int si,sj,ei,ej;
int n,nx,ny;
int x[N],y[N];
int g[N][N],step[N][N];
int t[4][2]={1,0,-1,0,0,1,0,-1}; struct node
{
int x1,x2,y1,y2;
}rect[N]; struct xiaohao
{
int xx,yy;
int step;
}e,w,xh[M]; int nextint()
{
int f=1;
char c;
while((c=getchar())<'0'||c>'9')
if(c=='-')
f=-1;
int sum=c-'0';
while((c=getchar())>='0'&&c<='9')
sum=sum*10+c-'0';
return sum*f;
} void lisanhua(int m) //离散化
{
int i,j;
sort(x+1,x+m+1);
sort(y+1,y+m+1);
nx=1;
for(i=2;i<=m;i++)//去重
if(x[i]!=x[i-1])
x[++nx]=x[i];
ny=1;
for(i=2;i<=m;i++)//去重
if(y[i]!=y[i-1])
y[++ny]=y[i];
} int getx(int xx)//数据量大的时候可以用二分查找
{
for(int i=1;i<=nx;i++)
if(x[i]==xx)
return i;
} int gety(int yy)
{
for(int i=1;i<=ny;i++)
if(y[i]==yy)
return i;
} void add(int x1,int x2,int y1,int y2)
{
int i,j;
for(i=x1;i<=x2;i++)
for(j=y1;j<=y2;j++)
g[i][j]=1;//建筑物标记为1
} void jiantu()
{
int i,j,x1,x2,y1,y2;
memset(g,0,sizeof(g));
si=getx(sx);
sj=gety(sy);
ei=getx(ex);
ej=gety(ey); for(i=si*3;i>=si*3-2;i--)//起点,这个地方9个格子全部要标记为5
for(j=sj*3;j>=sj*3-2;j--)
g[i][j]=5;
for(i=ei*3;i>=ei*3-2;i--)//终点,这个地方9个格子全部要标记为6
for(j=ej*3;j>=ej*3-2;j--)
g[i][j]=6; for(i=1;i<=n;i++)
{
x1=getx(rect[i].x1);
y1=gety(rect[i].y1);
x2=getx(rect[i].x2);
y2=gety(rect[i].y2); add(x1*3,x2*3-2,y1*3,y2*3-2);
}
for(i=1;i<=nx;i++)//将重合的点中间补上
for(j=1;j<=ny;j++)
{
if(g[i*3-2][j*3-2]==1&&g[i*3][j*3]==1||g[i*3-2][j*3]==1&&g[i*3][j*3-2]==1)
g[i*3-1][j*3-1]=1;
if(g[i*3-1][j*3-2]==1&&g[i*3-1][j*3]==1)
g[i*3-1][j*3-1]=1;
if(g[i*3-2][j*3-1]==1&&g[i*3][j*3-1]==1)
g[i*3-1][j*3-1]=1;
}
// for(i=1;i<=3*nx;i++) //输出离散化后的图
// {
// for(j=1;j<=3*ny;j++)
// printf("%d",g[i][j]);
// printf("\n");
// }
} bool ok(int tx,int ty)
{
return (tx>=0&&tx<=3*nx&&ty>=0&&ty<=3*ny);
} void BFS()
{
int i,j,head=0,tail=0;
w.step=-1;
for(i=si*3;i>=si*3-2;i--)
for(j=sj*3;j>=sj*3-2;j--)
if(g[i][j]==5)
{
w.xx=i;w.yy=j;
xh[tail++]=w;
}
memset(step,INF,sizeof(step));
step[w.xx][w.yy]=-1;
while(head!=tail)
{
e=xh[head++];
if(head==M)
head=0;
for(i=0;i<4;i++)
{
w=e;
w.step++;
int tx=w.xx+t[i][0];
int ty=w.yy+t[i][1];
while(ok(tx,ty)&&g[tx][ty]!=1)//判断是否在界内,而且能走
{
if(w.step<step[tx][ty])
{
if(g[tx][ty]==6)
{
printf("%d\n",w.step);
return ;
}
step[tx][ty]=w.step;
w.xx=tx;
w.yy=ty;
xh[tail++]=w;
if(tail==M)
tail=0;
}
tx+=t[i][0];
ty+=t[i][1];
}
}
}
printf("-1\n");
} int main()
{
int i,j;
while(scanf("%d%d%d%d",&sx,&sy,&ex,&ey))
{
int x1,x2,y1,y2,m;
if((!sx)&&(!sy)&&(!ex)&&(!ey))
break;
if(sx==ex&&sy==ey)
{
printf("0\n");
continue;
}
m=0;
rect[0].x1=x[++m]=sx;
rect[0].y1=y[m]=sy;
rect[0].x2=x[++m]=ex;
rect[0].y2=y[m]=ey;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
if(x1>x2)//防止有的数据先是右上点再是左下点
swap(x1,x2),swap(y1,y2); x[++m]=rect[i].x1=x1;
y[m]=rect[i].y1=y1;
x[++m]=rect[i].x2=x2;
y[m]=rect[i].y2=y2;
} lisanhua(m);
jiantu();
BFS();
}
return 0;
} /*
0 0 3 3
4
2 0 4 2
0 2 2 4
4 2 6 4
2 4 4 6 100 -50 10 20
4
-100 15 -20 30
-5 25 50 100
-30 -30 70 -20
70 -20 120 80 5 -1 60 7
3
1 8 101 888
0 0 49 5
50 0 100 6 0 -1 2 1
3
-1 0 0 1
0 1 1 2
1 -2 3 0 0 0 0 10
1
0 5 5 8 0 0 0 10
1
-3 5 0 8 0 0 0 10
2
0 5 5 8
0 2 4 5 0 0 0 10
2
0 5 5 8
-2 1 0 4 0 0 0 10
2
0 0 5 8
-2 1 0 5 0 0 1 10
0 0 -1 2 1
3
-1 0 0 1
0 1 1 2
1 -2 3 0 0 -1 -1 0
9
-3 4 4 5
4 -3 5 5
-2 -3 4 -2
-3 -3 -2 4
-1 2 0 4
1 1 3 3
0 0 1 1
-2 -2 0 0
2 -2 3 0 0 0 0 0 结果应该为:
-1
3
2
1
0
0
0
0
2
1
1
5
*/
上一篇:HDU 1142 A Walk Through the Forest(最短路+记忆化搜索)


下一篇:c读mysql产生乱码问题