HDU 4444 - Walk

22 篇文章 0 订阅

 

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

 

2012年ACMICPC金华赛区C题。

 

作为我们队主攻搜索和数据结构(线段树神马的经常接触离散化),当时我一看这题就有想法了,综合起来只敲了四十多分钟。(其间分身去把被卡了N久的水题A了)

 

我们队就是靠这题从铁直接飞到银牌。

 

思路很简单。

 

离散化边界为点。然后就是用普通的BFS去做。

 

需要储存每个边的四种状态:矩形上边界?矩形下边界?矩形左边界?矩形右边界? 

 

边拐角的问题不同于角拐角,有六种可能,比较难解决,需要多一想一想。

 

比较难通过的是我附录的最后一组测试数据。

 

当时比赛时犯2,判断以EOF结束,WA了两次。。。 没想到,回来之后在HDU交,还是犯2,又判断以EOF结束,再WA两次。。。

 

 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>

using namespace std;


int x[110],y[110];
int idx[110],idy[110];
int mp[210][210],path[210][210];
bool UP[210][210],DOWN[210][210],LEFT[210][210],RIGHT[210][210];
int ax,ay,bx,by;
int n,nn;
int mx,my;

struct QUE
{
	int x,y;
	QUE()
	{
		
	}
	QUE(int xx,int yy)
	{
		x=xx,y=yy;
	}
}que[200000];

int fx[]={1,0,0,-1,0,0,0,0,1,-1,1,-1};
int fy[]={0,1,-1,0,1,-1,1,-1,0,0,0,0};
int fz[]={0,0,0,0,1,1,-1,-1,-1,-1,1,1};

void turn(int ex,int ey,int rx,int ry,int &t,int p)
{
	int i,nx,ny;
	for(i=1;;i+=2)
	{
		nx=rx+ex*i;
		ny=ry+ey*i;
		if(nx<0 || ny<0 || nx>mx || ny>my)
		{
			return;
		}
		if(mp[nx][ny]>0)
		{
			return;
		}
		if(i>1 &&(UP[nx-ex][ny-ey]&&DOWN[nx-ex][ny-ey]&&(ny&1) || (nx&1)&&LEFT[nx-ex][ny-ey]&&RIGHT[nx-ex][ny-ey]))
		{
			return;
		}
		if(path[nx][ny]==-1)
		{
			que[++t]=QUE(nx,ny); 
			path[nx][ny]=p;
		}
		else if(path[nx][ny]<p)
		{
			return;
		}
	}	
}

int bfs()
{
	int s,t,k;
	int rx,ry;
	s=0;
	t=-1;
	for(k=0;k<4;k++)
	{
		turn(fx[k],fy[k],ax,ay,t,0);
	}
	while(s<=t)
	{
		rx=que[s].x;
		ry=que[s].y;
		++s;
		for(k=0;k<4;k++)
		{
			if(rx+fx[k]==bx && ry+fy[k]==by)
			{
				return path[rx][ry];
			}
		}
		if(rx&1)
		{
			for(k=4;k<8;k++)
			{
				if(UP[rx+fz[k]][ry]&&DOWN[rx+fz[k]][ry] || LEFT[rx+fz[k]][ry]&&RIGHT[rx+fz[k]][ry])
				{
					if(fy[k]<0 && RIGHT[rx][ry] || fy[k]>0 && LEFT[rx][ry])
					{
						continue;
					}
				}
				turn(fx[k],fy[k],rx+fz[k],ry,t,path[rx][ry]+1);
			}
		}
		else 
		{
			for(k=8;k<12;k++)
			{
				if(UP[rx][ry+fz[k]]&&DOWN[rx][ry+fz[k]] || LEFT[rx][ry+fz[k]]&&RIGHT[rx][ry+fz[k]])
				{
					if(fx[k]<0 && UP[rx][ry] || fx[k]>0 && DOWN[rx][ry])
					{
						continue;
					}
				}
				turn(fx[k],fy[k],rx,ry+fz[k],t,path[rx][ry]+1);
			}
		}
	}
	return -1;
}


int cmpx(int a,int b)
{
	return x[a]<x[b];
}

int cmpy(int a,int b)
{
	return y[a]<y[b];
}

void discretization()
{
	int i,tmp,now;
	nn+=2;
	for(i=0;i<nn;i++)
	{
		idx[i]=idy[i]=i;
	}
	sort(idx,idx+nn,cmpx);
	sort(idy,idy+nn,cmpy);

	tmp=-1000000000;
	now=0;
	for(i=0;i<nn;i++)
	{
		if(x[idx[i]]!=tmp)
		{
			tmp=x[idx[i]];
			now+=2;
		}
		x[idx[i]]=now;
	}
	mx=now+2;
	tmp=-1000000000;
	now=0;
	for(i=0;i<nn;i++)
	{
		if(y[idy[i]]!=tmp)
		{
			tmp=y[idy[i]];
			now+=2;
		}
		y[idy[i]]=now;
	}
	my=now+2;
	/* 
	cout<<"离散化结果: "<<endl;
	cout<<"x:   "; for(i=0;i<nn;i++) cout<<x[idx[i]]<<" ";cout<<endl;
	cout<<"y:   "; for(i=0;i<nn;i++) cout<<y[idy[i]]<<" ";cout<<endl;
	*/
	nn-=2;
	ax=x[nn];
	ay=y[nn];
	bx=x[nn+1];
	by=y[nn+1];
}

void INIT()
{
	int i,j,k;
	memset(mp,0,sizeof(mp));
	memset(path,-1,sizeof(path));
	memset(UP,0,sizeof(UP));
	memset(DOWN,0,sizeof(DOWN));
	memset(LEFT,0,sizeof(LEFT));
	memset(RIGHT,0,sizeof(RIGHT));
	for(i=0;i<n;i++)
	{
		for(j=x[i]+1;j<x[i+n];j++)
		{
			mp[j][y[i]+1]=mp[j][y[i+n]-1]=1;
		}
		for(j=y[i]+1;j<y[i+n];j++)
		{
			mp[x[i]+1][j]=mp[x[i+n]-1][j]=1;
		} 
		for(j=x[i];j<=x[i+n];j++)
		{
			LEFT[j][y[i]]=true;
			RIGHT[j][y[i+n]]=true;
		}
		for(j=y[i];j<=y[i+n];j++)
		{
			DOWN[x[i]][j]=true;
			UP[x[i+n]][j]=true;
		}
	}
	/*
	cout<<"打印地图:"<<endl;
	for(j=my-1;j>=0;j--)
	{
		for(i=0;i<mx;i++)
		{ // 2表示两点之间有不可走的边, 1表示两点之间有可走的边 , 0表示两点之间无边, .表示整数坐标点 
			if(i%2==0 && j%2==0) cout<<". ";
			else if(i%2==1 && j%2==1) cout<<"  ";
			else if(mp[i][j] || UP[i][j]&&DOWN[i][j] || LEFT[i][j]&&RIGHT[i][j]) cout<<"2 ";
			else cout<<(UP[i][j]||DOWN[i][j]||LEFT[i][j]||RIGHT[i][j])<<" ";
		}
		cout<<endl;
	}
	*/
}


int input()
{
	int i;
	int X1,X2,Y1,Y2;
	scanf("%d%d%d%d",&ax,&ay,&bx,&by);
	if(ax==0 && bx==0 && ay==0 && by==0)
	{
		return 0;
	}
	scanf("%d",&n);
	nn=n+n;
	for(i=0;i<n;i++)
	{
		scanf("%d%d%d%d",&X1,&Y1,&X2,&Y2);
		x[i]=min(X1,X2);
		x[i+n]=max(X1,X2);
		y[i]=min(Y1,Y2);
		y[i+n]=max(Y1,Y2);
	}
	x[nn]=ax;
	x[nn+1]=bx;
	y[nn]=ay;
	y[nn+1]=by;
	return 1;
}

int main()
{

	while(input())
	{
		discretization();
		if(ax==bx && ay==by)
		{
			puts("0");
			continue;
		}
		INIT();
		printf("%d\n",bfs());
		/*
		cout<<"打印路径:"<<endl; 
		for(int i=my;i>=0;i--)
		{
			for(int j=0;j<mx;j++)
			{
				printf("%3d",path[j][i]);
			}
			cout<<endl;
		}
		*/
	}
	return 0;
}

/*

// 绕路   2
1 1 1 4
1
0 2 2 3

// 直走  0
1 1 1 4
1
3 3 4 5 

// 沿着边直走  0
0 1 0 7
2
0 2 2 3
-1 4 0 5 

// 沿着边直走  0
0 1 0 7
2
0 2 2 3
0 3 2 4

// 无法穿过缝隙,绕路   2
0 1 0 7
2
0 2 2 3
-1 3 0 5 

// 无法到达  -1
0 0 5 5
4
-1 1 1 2
1 -1 2 1
-1 -1 1 -2
-1 1 -2 -1 



// 同点经过两次。  5
1 3 4 1
10
-1 -1 3 2
3 -1 7 0
7 -1 11 3
9 3 11 7
-1 7 11 9
0 5 4 7
-1 2 0 7
2 2 4 3
4 3 5 4
5 4 8 6

*/



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值