前言
一道极其考验耐心的模拟题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;
}