poj 2049 Finding Nemo 建图技巧型最短路

题意:

给一个由墙和门组成的迷宫,求从原点到目标点最少要经过多少道门。

分析:

有人用bfs来,结果写的是介于bfs和最短路中间不伦不类的算法。。这题边权为0或1,用bfs求最短路靠谱么??bfs是只能求边权恒定的最短路,这题用bfs过的是因为把bfs写成了spfa(spfa本来就是一种优化的bfs算法),bfs是什么?搜索,搜索的含义是搜到一个状态以后就不会再经过这个状态了,故在bfs里对任何状态只有把vis[s]置为1的过程,没有把vis[s]置0的过程。spfa的区别是同时有把vis[s]置0和置1的过程(所以可处理不定长边)。个人认为解题还是思路清晰一些好,不要过了就不管了。

另外这题的spfa比较特殊,没有置1的过程,这样会加入冗余节点,但保证了每个节点和到该节点方向的一致性。

代码:

//poj 2049
//sep9
#include <iostream>
#include <queue>
using namespace std;
const int maxN=205;

int dis[maxN][maxN],inq[maxN][maxN];
int g[maxN][maxN][4];
int wn,dn,startXI,startYI;
double startXF,startYF;
int dir[4][2]={{0,1},{0,-1},{-1,0},{1,0}};

struct node{
	int x,y,dir;	
};
queue<node> q;
int changeDir(int old)
{
	if(old==0) return 1;
	if(old==1) return 0;
	if(old==2) return 3;
	if(old==3) return 2;	
}
void spfa()
{
	while(!q.empty()) q.pop();
	memset(inq,0,sizeof(inq));
	node cur;
	cur.x=startXI,cur.y=startYI,cur.dir=-1;
	dis[startXI][startYI]=0;
	q.push(cur);
	inq[startXI][startYI]=1;
	
	while(!q.empty()){
		cur=q.front();q.pop();
		int x=cur.x,y=cur.y,steps=dis[x][y];
		inq[x][y]=0;
		if(x==0&&y==1)	continue;
		
		for(int d=0;d<4;++d){
			if(d==cur.dir) continue;
			if(g[x][y][d]==1) continue;
			int newx=x+dir[d][0];
			int newy=y+dir[d][1];
			if(newx<0||newx>202||newy<0||newy>202) continue;
			int newdir=changeDir(d);
			int newsteps;
			if(g[x][y][d]==2) newsteps=steps+1;
			else newsteps=steps;
		 	
			if(newsteps>dis[0][1]) continue;
			
			if(newsteps<dis[newx][newy]){
				dis[newx][newy]=newsteps;
				if(!inq[newx][newy]){
					node ncur;
					ncur.x=newx,ncur.y=newy,ncur.dir=newdir;
					q.push(ncur);
				}
			}	
		}
	}
}

int main()
{
	while(scanf("%d%d",&wn,&dn)==2){
		if(wn==-1&&dn==-1)
			break;
		for(int i=0;i<maxN;++i)
			for(int j=0;j<maxN;++j) 
				dis[i][j]=INT_MAX;
		memset(g,0,sizeof(g));
		int x,y,d,t;
		while(wn--){
			cin>>x>>y>>d>>t;
			if(d==1)
		 		for(int j=y+1;j<=y+t;++j)
		 			g[x][j][2]=g[x-1][j][3]=1;
	 		else
			 	for(int j=x;j<x+t;++j)
				 	g[j][y][0]=g[j][y+1][1]=1;	
		}
		while(dn--){
			cin>>x>>y>>d;
			if(d==1)
				g[x][y+1][2]=g[x-1][y+1][3]=2;
			else
				g[x][y+1][1]=g[x][y][0]=2;			
		}	
		cin>>startXF>>startYF;
		startXI=(int)startXF;
		startYI=(int)startYF+1;
		if(startXI<0||startXI>199||startYI<0||startYI>199)
			cout<<0<<endl;
		else{
			spfa();
			if(dis[0][1]==INT_MAX) cout<<-1<<endl;
			else cout<<dis[0][1]<<endl;
		}
	}
	return 0;	
} 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值