P2243 电路维修

看了眼题解,貌似没有和我的思路一样的…
所以就来写一篇题解…
首先我不会什么双向BFS也懒得写最短路…
所以,就一个BFS 闯遍天下
先看题:

感性理解一下…貌似如(1,2),(2,1),(1,4),(4,1)都到不了 虽然这个么什么用
好了,进入主题
首先,BFS是一个队列,为了保证结果的真确性,所以存当前花费的数组必须符合单调性,不然就没法达到最短路的效果了(开始就是没注意单调,调了2个小时)可以发现一个点可以直接到四个点,而到这四个点所花费的次数为1或0,所以只要当队伍中有一个点Q时,把Q可以花费0次就可以到达的点全部放进队列,然后,就是一个裸的BFS最短路了…

#include<bits/stdc++.h>
using namespace std;
int queue_spend[1000000];//队列中每个位置的最少花费
int queue_x[1000000],queue_y[1000000];//队列中的点
int tail,head,N,M;
int boo[605][605];
int _map[605][605];
//注意:boo判断的是点,_map判断的是边
/*
B   C
 \ /
  A
 / \
D   E
A点存的是A这个点和A-E这条边
*/
int now_spead;//记录当前的花费
void add(int x,int y,int spend)//加入队列
{
	queue_x[++tail]=x;
	queue_y[tail]=y;
	queue_spend[tail]=spend;
	boo[x][y]=0;
}
void around(int first_x,int first_y)//向四周寻找可以不花费就可以到的点
{
	if(boo[first_x-1][first_y-1]&&_map[first_x-1][first_y-1]==0)
	//注意当坐标是减时,存边和存点都是减;加时,存边就是当前点对应的边
	{add(first_x-1,first_y-1,now_spead);around(first_x-1,first_y-1);}
	if(boo[first_x+1][first_y+1]&&_map[first_x][first_y]==0)
	{add(first_x+1,first_y+1,now_spead);around(first_x+1,first_y+1);}
	if(boo[first_x+1][first_y-1]&&_map[first_x][first_y-1]==1)
	{add(first_x+1,first_y-1,now_spead);around(first_x+1,first_y-1);}
	if(boo[first_x-1][first_y+1]&&_map[first_x-1][first_y]==1)
	{add(first_x-1,first_y+1,now_spead);around(first_x-1,first_y+1);}
}
void write(int out)//输出
{cout<<out<<endl;}
void solve()
{
	int i,j;
	for(i=0;i<=N+2;i++)//把表赋空
	for(j=0;j<=M+2;j++)
	boo[i][j]=0;
	cin>>N>>M;
	char ch;
	for(i=1;i<=N;i++)//读入
	for(j=1;j<=M;j++)
	{
		cin>>ch;
		if(ch=='/')_map[i][j]=1;//记录下边
		else _map[i][j]=0;
		//记录下点
		boo[i][j]=1;
		if(i==N)
		boo[i+1][j]=1;
		if(j==M)
		boo[i][j+1]=1;
		if(i==N&&j==M)
		boo[i+1][j+1]=1;
	}
	//队列初始化
	tail=1;
	head=0;
	boo[1][1]=0;
	now_spead=0;
	around(queue_x[1],queue_y[1]);//把一开始就可以直接到达的点放入队列,并且花费是0
	while((++head)<=tail)
	{
		if(queue_x[head]==N+1&&queue_y[head]==M+1)//找到结果
		{
			write(queue_spend[head]);
			return;
		}
		if(_map[queue_x[head]-1][queue_y[head]-1]==1&&boo[queue_x[head]-1][queue_y[head]-1])//如果这个方向行走要花费1次的话就入队,比较用0次的早入队了
		{
			add(queue_x[head]-1,queue_y[head]-1,queue_spend[head]+1);
			now_spead=queue_spend[tail];
			around(queue_x[tail],queue_y[tail]);//注意这里一定就要把拓展做掉,不然凉凉,我就是在在这里被卡了
		}
		if(_map[queue_x[head]][queue_y[head]]==1&&boo[queue_x[head]+1][queue_y[head]+1])//以下同理
		{
			add(queue_x[head]+1,queue_y[head]+1,queue_spend[head]+1);
			now_spead=queue_spend[tail];
			around(queue_x[tail],queue_y[tail]);
		}
		if(_map[queue_x[head]-1][queue_y[head]]==0&&boo[queue_x[head]-1][queue_y[head]+1])
		{
			add(queue_x[head]-1,queue_y[head]+1,queue_spend[head]+1);
			now_spead=queue_spend[tail];
			around(queue_x[tail],queue_y[tail]);
		}
		if(_map[queue_x[head]][queue_y[head]-1]==0&&boo[queue_x[head]+1][queue_y[head]-1])
		{
			add(queue_x[head]+1,queue_y[head]-1,queue_spend[head]+1);
			now_spead=queue_spend[tail];
			around(queue_x[tail],queue_y[tail]);
		}
	}
	cout<<"NO SOLUTION"<<endl;//无解
}
int main()
{
	//这里一直都不会改,就直接放在队伍中
	queue_x[1]=1;
	queue_y[1]=1;
	queue_spend[1]=0;
	int T;
	cin>>T;//进行T次操作
	int i;
	for(i=1;i<=T;i++)
	solve();
}

QAQ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值