Luogu P1979 华容道

5 篇文章 0 订阅
4 篇文章 0 订阅
Luogu P1979 华容道

心血来潮水篇博客
2019.9.25
一开始瞄着30分打了个bfs暴力
一测60(开心)
WA了两个点(是我忘记判断起点=终点了。。)
改了就70
贴一下

#include<cstdio>
#include<cstring>

using namespace std;

int ans=-1,tx,ty;
int n,m,q,a[1010][1010];
struct nod1{int ex,ey,sx,sy,t;}d[5000100];
int dx[4]={0,-1,0,1};
int dy[4]={-1,0,1,0};
int f[110][110][110][110];

void bfs()
{
	int head=1,tail=2;
	d[1].t=0;
	f[d[1].ex][d[1].ey][d[1].sx][d[1].sy]=1;
	while(head!=tail)
	{
		int x=d[head].ex;
		int y=d[head].ey;
		for(int i=0;i<4;i++)
		{
			int xx=x+dx[i];
			int yy=y+dy[i];
			if(a[xx][yy]==0||xx<1||yy<1||xx>n||yy>m)continue;
			d[tail]=d[head];
			if(xx==d[head].sx&&yy==d[head].sy)
			{
				d[tail].sx=x;d[tail].sy=y;
				if(x==tx&&y==ty)
				{
					ans=d[head].t+1;
					return ;
				}
			}
			d[tail].ex=xx;
			d[tail].ey=yy;
			d[tail].t=d[head].t+1;
			if(f[d[tail].ex][d[tail].ey][d[tail].sx][d[tail].sy]==1)continue;
			f[d[tail].ex][d[tail].ey][d[tail].sx][d[tail].sy]=1;
			tail++;
		}
		head++;
	}
}

int main()
{
	//freopen("ddd.in","r",stdin);
	//freopen("mee.out","w",stdout);
	scanf("%d %d %d",&n,&m,&q);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&a[i][j]);
		}
	}
	for(int i=1;i<=q;i++)
	{
		scanf("%d %d %d %d %d %d",&d[1].ex,&d[1].ey,&d[1].sx,&d[1].sy,&tx,&ty);
		if(d[1].sx==tx&&d[1].sy==ty)
		{
			printf("0\n");continue;
		}
		ans=-1;
		for(int l1=1;l1<=n;l1++)
			for(int l2=1;l2<=m;l2++)
				for(int l3=1;l3<=n;l3++)
					for(int l4=1;l4<=m;l4++)
						f[l1][l2][l3][l4]=0;
		bfs();
		printf("%d\n",ans);
	}
}

然后我试图看懂题解
然后放弃了…

2019.9.28
好 我卷土重来了
一篇详细的题解
明白了 思路清晰了
码了一会 ->80
QAQ查出来我是bfs不判起点=终点
然后A了
顺便把思路打在代码里了

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int maxn=0x3f3f3f3f;
int a[1010][1010];
int dx[5]={-1,1,0,0,0};
int dy[5]={0,0,-1,1,0};//上下左右 
//最后的两个零是为了check自己啊哈 
int v[1010][1010];
struct nod1{int x,y,t;}d[100100];
int vv[100100],dis[100100],f[100100];
struct nod2{int y,c,next;}b[100100];
int first[100100],len=0;
int ans=0x3f3f3f3f,n,m,q;
int nowx,nowy,bx,by,gox,goy;

void ins(int x,int y,int c)
{
	len++;
	b[len].y=y;
	b[len].c=c;
	b[len].next=first[x];
	first[x]=len;
} 

int id(int x,int y,int k)
{
	return ((x-1)*m+y)*4-(4-k);
}

int check(int x,int y,int k)
{
	
	int xx=x+dx[k];
	int yy=y+dy[k];
	if(xx<1||xx>n||yy<1||yy>m||a[xx][yy]==0)return 0;
	return 1; 
} 

int bfs(int sx,int sy,int nox,int noy,int ex,int ey)
//出发点 不能走 终点 
{
	if(sx==ex&&sy==ey)return 0;//!!!!!WA成80的原因 记住!!! 
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			v[i][j]=0;
	v[sx][sy]=1;
	d[1].x=sx;d[1].y=sy;
	d[1].t=0;
	int head=1,tail=2;
	while(head<tail)
	{
		int x=d[head].x,y=d[head].y;
		for(int i=0;i<4;i++)
		{
			int xx=x+dx[i];
			int yy=y+dy[i];
			if(xx==ex&&yy==ey)return d[head].t+1;
			if(v[xx][yy]==1||check(x,y,i)==0||(xx==nox&&yy==noy))continue;
			v[xx][yy]=1;
			d[tail].t=d[head].t+1;
			d[tail].x=xx;
			d[tail].y=yy;
			tail++;
		}
		head++;
	}
	return maxn;
} 

void pre()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(a[i][j]==0)continue;
			for(int k=0;k<4;k++)
			{
				if(check(i,j,k)==0)continue;
				for(int p=k+1;p<4;p++)
				{
					if(check(i,j,p)==0)continue;
					int step=bfs(i+dx[k],j+dy[k],i,j,i+dx[p],j+dy[p]);
					if(step==maxn)continue;
					ins(id(i,j,k),id(i,j,p),step);
					ins(id(i,j,p),id(i,j,k),step);
				}
			} 
		}
	}//四个方向转换
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(a[i][j]==0)continue;
			if(check(i,j,1))
			{
				ins(id(i,j,1),id(i+1,j,0),1);
				ins(id(i+1,j,0),id(i,j,1),1);
				
			}
			if(check(i,j,3))
			{
				ins(id(i,j,3),id(i,j+1,2),1);
				ins(id(i,j+1,2),id(i,j,3),1);
			} 
		}
	}//上下/左右换 
}

void find()
{
	int head=1,tail=1;
	for(int i=1;i<=n*m*4;i++)
	{
		dis[i]=0x3f3f3f3f;vv[i]=0;
	}
	for(int i=0;i<4;i++)
	{
		if(check(nowx,nowy,i))
		{
			int xx=nowx+dx[i];
			int yy=nowy+dy[i];
			int step=bfs(bx,by,nowx,nowy,xx,yy);
			if(step==maxn)continue;
			int ip=id(nowx,nowy,i);
			f[tail]=ip;
			dis[ip]=step;
			vv[ip]=1; 
			tail++;
		} 
	}//白格子先走到现在格子附近 
	while(head<tail)
	{
		int x=f[head];
		for(int i=first[x];i;i=b[i].next)
		{
			int y=b[i].y;
			if(dis[y]>dis[x]+b[i].c)
			{
				dis[y]=dis[x]+b[i].c;
				if(vv[y]==0)
				{
					vv[y]=1;
					f[tail]=y;
					tail++;
				}
			}
		}
		head++;
		vv[x]=0;
	}//spfa 
	ans=0x3f3f3f3f;
	for(int i=0;i<4;i++)
	{
		if(check(gox,goy,i)==0)continue;
		ans=min(dis[id(gox,goy,i)],ans);
	}
	if(ans==maxn)
		printf("-1\n");
	else
	printf("%d\n",ans);
}

int main()
{
	scanf("%d %d %d",&n,&m,&q);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	pre();
	//先预处理出
	//1.每个格子上下左右转换的步数,建边 
	//2.每个格子:白格子在下的状态 和 这个格子下一个格子(x+1,y)白格子在上的状态 建值=1的边[上下交换]
	//3.每个格子:白格子在右的状态 和 这个格子右一个格子(x,y+1)白格子在左的状态 建值=1的边[左右交换]
	for(int i=1;i<=q;i++)
	{
		scanf("%d %d %d %d %d %d",&bx,&by,&nowx,&nowy,&gox,&goy);
		if(nowx==gox&&nowy==goy)
		{
			printf("0\n");
			continue;
		}
		if(check(nowx,nowy,4)==0||check(gox,goy,4)==0)
		{
			printf("-1\n");
			continue;
		}
		find();
		//先把白格子跑到目标格子附近四个格子(bfs处理步数),再开始跑spfa 
	}
}
//本题是状态做点 步数为边权建图(好厉害!) 
//一定要记住判断起点等于终点噢 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值