【模拟-搜索】中山纪念中学暑期游Day5——输油管道

前言

一道极其考验耐心的模拟题or搜索题,还好我码代码时全程怀着【不怕,慢慢打】的心态,

最后功夫不负有心人,得了90%的分,

有一个数据点因为特殊情况考虑不周WA了...还是细节处理不好...

题目

请你帮忙设计一个从城市M到城市Z的输油管道,现在已经把整个区域划分为R行C列,每个单元格可能是空的也可能是以下7种基本管道之一:
  

  油从城市M流向Z,‘+’型管道比较特殊,因为石油必须在两个方向(垂直和水平)上传输,如下图所示:

        


  现在恐怖分子弄到了输油管道的设计图,并把其中一个单元格中的管道偷走了,请你帮忙找到偷走的管道的位置以及形状。

Input

  第一行包含两个整数R和C(1<=R,C<=25)。
  接下来R行每行C个字符描述被偷之后的形状,字符分为以下三种:
  (1)‘.’表示空;
  (2)字符‘|’(ASCII为124)、‘-’、‘+’、‘1’、‘2’、‘3’、‘4’描述管道的形状;
  (3)‘M’和‘Z’表示城市,两个都是只出现一次。
  输入保证石油的流向是唯一的,只有一个管道跟M和Z相连,除此此外,保证没有多余的管道,也就是说所有的管道在加进被偷的管道后一定都会被用上。
  输入保证有解而且是唯一的。

Output

  输出被偷走的管道的行号和列号以及管道的类型。

Sample Input

输入1:
3 7
.......
.M-.-Z.
.......

输入2:
3 5
..1-M
1-+..
Z.23.

输入3:
6 10
Z.1----4..
|.|....|..
|..14..M..
2-+++4....
..2323....
..........

Sample Output

输出1:
2 4 -

输出2:
2 4 4

输出3:
3 3 |

分析

我的思路:先从起点开始搜索一边,发现断点(没有管道接上)就记录位置,枚举每种管道放进断点,再搜索看走不走的通

如果能顺利从起点到终点就输出枚举到的管道

佩服自己居然能想到处理十字形管道的方法,而且简单:十字形管道要被经过两遍,而题目保证每个管道被完全利用,所以对每个“+”管道记录油经过的次数cnt[ i ][ j ]即可,最后判断每个cnt是否都>=2,是的话则答案合法

记得特判情况:"M.Z"或者M和Z上下相邻


听了评讲,有个兄弟的方法更简单且节省时间:也是先搜索,找断点,但是找到断点再通过其上下左右管道的形状来确定该断点应该放什么管道

也得特判"M.Z"或者M和Z上下相邻

代码

解释一下dir=1,2,3,4的意思:

1—上,2—右,3—下,4—左

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=25;
char a[MAXN+5][MAXN+5];
int v[MAXN+5][MAXN+5];
int dir1[5]={-1,0,1,0},dir2[5]={0,1,0,-1};
int n,m;
int sx,sy,tx,ty,fx,fy,f1,f2,ok;
void dfs(int x,int y,int dir)
{//dir表示四个运输过来的方向 
	if(a[x][y]=='Z')
		return ;
	if(a[x][y]=='.')
	{
		fx=x,fy=y;
		return ;
	}
	int flag=0;
	if(a[x][y]=='|')
	{
		if(dir==1) dfs(x-1,y,1);
		if(dir==3) dfs(x+1,y,3);
	}
	if(a[x][y]=='-')
	{
		if(dir==2) dfs(x,y+1,2);
		if(dir==4) dfs(x,y-1,4);
	}
	if(a[x][y]=='+')
	{
		if(dir==1) dfs(x-1,y,1);
		if(dir==2) dfs(x,y+1,2);
		if(dir==3) dfs(x+1,y,3);
		if(dir==4) dfs(x,y-1,4);
	}
	if(a[x][y]=='1')
	{
		if(dir==1) dfs(x,y+1,2);
		if(dir==4) dfs(x+1,y,3);
	}
	if(a[x][y]=='2')
	{
		if(dir==3) dfs(x,y+1,2);
		if(dir==4) dfs(x-1,y,1);
	}
	if(a[x][y]=='3')
	{
		if(dir==2) dfs(x-1,y,1);
		if(dir==3) dfs(x,y-1,4);
	}
	if(a[x][y]=='4')
	{
		if(dir==1) dfs(x,y-1,4);
		if(dir==2) dfs(x+1,y,3);
	}
	//printf("x:%d y:%d tmp:%d f:%d\n",dx,dy,tmp,flag);		
}
void DFS(int x,int y,int dir)
{
	if(!(1<=x&&x<=n&&1<=y&&y<=m))
		return ;
	if(a[x][y]=='Z')
	{
		ok=1;
		return ;
	}
	if(a[x][y]=='.')
		return ;
		
	if(a[x][y]=='|')
	{
		if(dir==1) DFS(x-1,y,1);
		if(dir==3) DFS(x+1,y,3);
		if(dir==2||dir==4) return ;
	}
	if(a[x][y]=='-')
	{
		if(dir==2) DFS(x,y+1,2);
		if(dir==4) DFS(x,y-1,4);
		if(dir==1||dir==3) return ;
	}
	if(a[x][y]=='+')
	{
		v[x][y]++;//这里要注意,用来判断'+'的 
		if(dir==1) DFS(x-1,y,1);
		if(dir==2) DFS(x,y+1,2);
		if(dir==3) DFS(x+1,y,3);
		if(dir==4) DFS(x,y-1,4);
	}
	if(a[x][y]=='1')
	{
		if(dir==1) DFS(x,y+1,2);
		if(dir==4) DFS(x+1,y,3);
		if(dir==2||dir==3) return ;
	}
	if(a[x][y]=='2')
	{
		if(dir==3) DFS(x,y+1,2);
		if(dir==4) DFS(x-1,y,1);
		if(dir==1||dir==2) return ;
	}
	if(a[x][y]=='3')
	{
		if(dir==2) DFS(x-1,y,1);
		if(dir==3) DFS(x,y-1,4);
		if(dir==1||dir==4) return ;
	}
	if(a[x][y]=='4')
	{
		if(dir==1) DFS(x,y-1,4);
		if(dir==2) DFS(x+1,y,3);
		if(dir==3||dir==4) return ;
	}
}
bool check()
{
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(a[i][j]=='+'&&v[i][j]<=1)
				return false;
	return true;
}
int get_ans(char x)
{
	ok=0;
	memset(v,0,sizeof(v));
	a[fx][fy]=x;
	if(a[sx-1][sy]!='.'&&a[sx-1][sy]!='Z') DFS(sx-1,sy,1);
	if(a[sx][sy+1]!='.'&&a[sx][sy+1]!='Z') DFS(sx,sy+1,2);
	if(a[sx+1][sy]!='.'&&a[sx+1][sy]!='Z') DFS(sx+1,sy,3);
	if(a[sx][sy-1]!='.'&&a[sx][sy-1]!='Z') DFS(sx,sy-1,4);
	if(ok==1&&check())
	{
		printf("%d %d %c",fx,fy,x);
		exit(0);
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",a[i]+1);
		for(int j=1;j<=m;j++)
		{
			if(a[i][j]=='M')
				sx=i,sy=j;
			if(a[i][j]=='Z')
				tx=i,ty=j;
		}
	}
	if(a[sx-1][sy]!='.'&&a[sx-1][sy]!='Z') dfs(sx-1,sy,1);
	if(a[sx][sy+1]!='.'&&a[sx][sy+1]!='Z') dfs(sx,sy+1,2);
	if(a[sx+1][sy]!='.'&&a[sx+1][sy]!='Z') dfs(sx+1,sy,3);
	if(a[sx][sy-1]!='.'&&a[sx][sy-1]!='Z') dfs(sx,sy-1,4);
	get_ans('|');
	get_ans('-');
	get_ans('+');
	get_ans('1');
	get_ans('2');
	get_ans('3');
	get_ans('4');
	return 0;
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值