近期所做题目中最好的一道,首先是比较创新不是常规的,另外需要比较好的数学功底能够洞察到一些小细节,然后转化方法貌似有很多,我自己想了很多但是都很差劲,最后实在没办法很无耻地找了解题报告,这篇解题报告感觉写得最好,我就是按照他的思路自己写的代码1A,佩服佩服此大神
解题报告 http://hi.baidu.com/lixubd/item/1fbebd2c0389700f43634a5f
算法思路都在里面了,我就不写了,我自己独立写了代码,加了很多注释,代码虽然比较多(这道题代码本来就多),然后其实不难读懂
说明一点,预处理后的矩阵行和列都翻倍了,我的代码行和列都是从1开始标号的,而那位大神的代码都是从0开始标号的,不同
有一点这里说明一下,水平和垂直的上下左右移动没什么问题,直接递归搜索就好
但是,但是,但是,就是斜向移动,左上,右上,左下,右下,四个方向,每个方向都是有两种情况,也就是有8个情况了,8中情况对当前点的横纵坐标是有要求的,有的情况要求横坐标为奇数纵坐标为偶数,有的要求横坐标偶数纵坐标奇数,有的要求横纵都是奇数,有的要求横纵都是偶数,总之这8个人情况对当前点的横纵坐标的奇偶性的要求是不同,每种情况都需要独立判断,不是统一的,至于没什么,其实只要画图出来就可以了,这里不说明白
提示一下,原始矩阵是n*m(行*列),一个格子输入一个斜杆,然后这个矩阵翻倍变成2n*2m,再对应一下这8中情况当前点的位置,是在偶数行呢还是奇数行呢?是在奇数列呢还是偶数列呢?然后就明白了哈哈哈哈
#include <cstdio> #include <cstring> #define MAX 160 //长宽最多为75,翻倍为150 bool g[MAX][MAX]; bool vis[MAX][MAX]; int n,m; //原始长宽 int dd[9][2]={{0,0},{-1,0},{1,0},{0,-1},{0,1},{-1,-1},{-1,1},{1,-1},{1,1}}; //12345678表示八个方向,上下左右,左上,右上,左下,右下; int max,ccount,c,FIND; void input() { memset(g,0,sizeof(g)); memset(vis,0,sizeof(vis)); for(int i=0; i<=2*m+1; i++) //翻倍后的迷宫的上下外围不能访问 g[0][i]=g[2*n+1][i]=1; for(int i=0; i<=2*n+1; i++) //翻倍后的迷宫的左右外围不能访问 g[i][0]=g[i][2*m+1]=1; for(int i=1; i<=n; i++) //原始迷宫的i行 { char s[MAX]; scanf("%s",s+1); for(int j=1; j<=m; j++) if(s[j]=='/') { g[2*i][(2*j)-1]=1; g[(2*i)-1][2*j]=1; } else { g[2*i][2*j]=1; g[(2*i)-1][(2*j)-1]=1; } } /* for(int i=1; i<=2*n; i++) { for(int j=1; j<=2*m; j++) printf("%d ",g[i][j]); printf("\n"); } */ return ; } void dfs(int x ,int y) { vis[x][y]=1; c++;//格子数计数 if(x==1 || x==2*n || y==1 || y==2*m) FIND=0; //如果成环的话,一定不会到达矩阵的边界,因为一定有斜杆包围起来的,到了边界不可能有斜杆包围 //虽然不是环但是不能就此返回,一定要把这个连通分量全部搜索完,仅仅是改变FIND表示这个连通分量不是一个环 for(int i=1; i<=8; i++) //枚举8个可能的方向 { int xx,yy; //将要移向的格子的坐标 xx=x+dd[i][0]; yy=y+dd[i][1]; if(!g[xx][yy] && !vis[xx][yy]) //新格子是可以到达的,而且没有被访问过的 { if(i<=4) //前四个方向是上下左右,不需要做什么特殊判断,直接递归 dfs(xx,yy); else //斜方向 { if(i==5) //左上 { if( (g[x][y-1]&&g[x-1][y-2])&& (g[x][y+1]&&g[x-1][y])&& !(x&1)&&(y&1) || (g[x-1][y]&&g[x-2][y-1])&& (g[x+1][y]&&g[x][y-1])&& (x&1)&&!(y&1) ) dfs(xx,yy); } else if(i==6) //右上 { if((g[x][y-1]&&g[x-1][y])&& (g[x][y+1]&&g[x-1][y+2])&& !(x&1)&&!(y&1) || (g[x-1][y]&&g[x-2][y+1])&& (g[x+1][y]&&g[x][y+1])&& (x&1)&&(y&1) ) dfs(xx,yy); } else if(i==7) //左下 { if( (g[x][y-1]&&g[x+1][y-2])&& (g[x][y+1]&&g[x+1][y])&& (x&1)&&(y&1)|| (g[x][y-1]&&g[x-1][y])&& (g[x+1][y]&&g[x+2][y-1])&& !(x&1)&&!(y&1)) dfs(xx,yy); } else //右下 { if( (g[x][y-1]&&g[x+1][y])&& (g[x][y+1]&&g[x+1][y+2])&& (x&1)&& !(y&1) || (g[x-1][y]&&g[x][y+1])&& (g[x+1][y]&&g[x+2][y+1])&& !(x&1)&& (y&1) ) dfs(xx,yy); } } } } return ; } void solve() { //dfs,每次搜索其实都搜完了一个连通分量,其实等同于图的遍历 max=ccount=0; for(int i=1; i<=2*n; i++) for(int j=1; j<2*m; j++) if(!g[i][j]) if(!vis[i][j]) { c=0; FIND=1; dfs(i,j); if(FIND) { ccount++; if(c>max) max=c; } } return ; } int main() { int T=0; while(scanf("%d%d",&m,&n) && n && m) //先宽再长 { input(); solve(); T++; printf("Maze #%d:\n",T); if(!ccount) printf("There are no cycles.\n"); else printf("%d Cycles; the longest has length %d.\n",ccount,max); printf("\n"); } return 0; }