HDU 4444 Walk (离散化建图+BFS+记忆化搜索) 绝对经典
2013-08-06 17:28
239 查看
题目地址: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
,y
;
int g
,step
;
int t[4][2]={1,0,-1,0,0,1,0,-1};
struct node
{
int x1,x2,y1,y2;
}rect
;
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
*/
题意:给你一些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
,y
;
int g
,step
;
int t[4][2]={1,0,-1,0,0,1,0,-1};
struct node
{
int x1,x2,y1,y2;
}rect
;
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 4444 Walk (离散化建图+BFS+记忆化搜索) 绝对经典
- 看一个大男人是怎样处理家庭矛盾的(绝对经典)(转)
- Java基础知识总结(绝对经典)
- 读书【绝对经典】
- [转]QQ经典签名100句 - [绝对经典]
- 经典SQL语句大全(绝对的经典)
- 绝对经典-- C++初学者必看的50个建议
- 不可不读的绝对英文经典
- Java基础知识总结(绝对经典)
- 考研十大必备(现实版)绝对经典
- 绝对经典的 xml 工具 完美破解
- 绝对经典的表记录操作(超越整理)
- 好歌推荐 绝对经典(中外结合)
- 分享经典语句 绝对受益匪浅
- 绝对经典Java开源工具Jimi处理图片大小及格式转换及打水印(源码)
- Eclips使用秘技(绝对经典)
- As We May Think ---- 绝对经典的预言
- 经典XP技巧 绝对对你有用
- 绝对经典 C++初学者必看的50个建议
- ASP.NET 2.0 新手SQL存储过程简单实例入门 绝对经典入门