本题的亮点是dfs和‘\’ ‘/’的转化方法。我采用了比较普遍和简单的方法,使用九宫格,这样由于斜着走可以变成横着走和竖着走的组合形式,所以在移步遍历时只用考虑上下左右四个方向。
编程步骤可分为三步:
(1)输入:通过键盘输入‘\’ ‘/’,将‘\’转化为100 010 001 ,‘/’ 转化为 001 010 100,构造map数组。
(2)dfs:判断移动一步之后,是否超过了边界,由此筛出非封闭点,check标志位标记是否封闭;
另外为了提高效率,还可以设置非封闭已遍历点,即与边界相通的点,逐步扩大边界范围;
此处还有一个教训:开始把row写成x把col写成y,导致想成坐标,结果此处h和w的位置写反。。。。
(3)寻找Cycles数和最大长度:寻找未遍历且map值为0的点,进行dfs。
做完此题后受益匪浅啊。
代码码:
#include<iostream>
#include<stdio.h>
#include<string.h>//memset函数的头文件
using namespace std;
int w,h,length,check=1;//宽,高,围住的方块数,标志位
int num=0;//Maze数
int visit[250][250];//75*3=225
int map[250][250];//visit为访问数组,记录该方块是否被访问过;map为输入数组,记录0,1的位置
int Move[4][2]={1,0,-1,0,0,1,0,-1};//移动的方向,由于采用九宫格,只需考虑上下左右四个方向
void dfs(int row,int col,int &len){//dfs 开始把row写成x把col写成y,导致想成坐标
int R,C;//R是行,C是列
for (int i=0;i<4;i++){
R=row+Move[i][0];
C=col+Move[i][1];
if ((R>=0)&&(R<3*h)&&(C>=0)&&(C<3*w)){//开始把row写成x把col写成y,导致想成坐标,结果此处h和w的位置写反。。。。
if (visit[R][C]==0&&map[R][C]==0){
visit[R][C]=1;
len++;
dfs(R,C,len);
}
}
else check=0;
}
}
int main(){
int cycles,max;
while(scanf("%d%d",&w,&h)){
max=0;
if (w+h==0) break;//输入0 0时的结果:无输出
memset(map,0,sizeof(map));memset(visit,0,sizeof(visit));//清空map和visit
num++;
for(int i=0;i<h;i++)//输入map
for(int j=0;j<w;j++){
char ch;cin>>ch;
if (ch=='\\'){
map[3*i][3*j]=1;map[3*i+1][3*j+1]=1;map[3*i+2][3*j+2]=1;
}
else if (ch=='/'){
map[3*i][3*j+2]=1;map[3*i+1][3*j+1]=1;map[3*i+2][3*j]=1;
}
}
cycles=0;
for(int i=0;i<3*h;i++)
for(int j=0;j<3*w;j++){
length=1;//已知一点判断下一点
if (visit[i][j]==0&&map[i][j]==0){
visit[i][j]=1;check=1;dfs(i,j,length);
if (check==1){
cycles++;
if (length>max) max=length;
}
}
}
cout<<"Maze #"<<num<<":"<<endl;
if (cycles>0) cout<<cycles<<" Cycles; the longest has length "<<max/3<<'.'<<endl;//注意格式
else cout<<"There are no cycles."<<endl;
cout<<endl;
}
return 0;}
ps:编程过程中查阅的一些资料:
(1)数组的存储方式。
PASCAL和C语言中,数组按行优先顺序存储。
FORTRAN语言中,数组按列优先顺序存储。
(2)输入那点儿事:
cin.get()是保留回车在输入流队列中的.而cin是丢弃回车的.
所以cin.get()在下一次输入之前需要把之前的回车符给弄掉。