/*水管工游戏
一块快矩形的土地 被分成N*M的单位正方形 现在这个土地上已经买有一些水管水管将从(1,1)的左上方 延伸到(N,M)d的矩形下方的右下角右部边缘
水管只有两种
"┛","━"
上方的外部方格代表单位正方形 内部的代表水管
每个水管占据一个单位正方形 你要做的就是旋转这些管道
使其可以连接成一个管道通路 即创造一条可以从(1,1)到(N,M)的连通管道
标有树木的方格代表这里没有管道 树木用▲表示
解:为了便于描述 我们用数字代表水管的状态
{"▲","┗","┎","┓","┛","━","┃"}
0 1 2 3 4 5 6 数字上方与图案对应
前四个为弯管的四种状态 后两个为直管的两种状态EG:在另一个文件有图片 首先是(1,1) 假设其是直管 则只能用5号管子这种状态
其次为(1,2) 是弯管 进水口在左边 因此(1,2)的水管有两种方式 上面的第3种和第4种
先尝试3这种方法 之后到达 (2,2) (2,2)是直管只能是6这种方式。。。。
就这么尝试下去 直到(N,M+1)结束 便产生一种方案
所以用深度遍历的搜索方法来解决比较适合
我们来用上面的那六种 枚举一下
对于一个水管 如果是直管 则进水口在左边或右边只能用 5这种方式 如果是在上下两边则直接为6
而进水口是通过前一个水管来判断的 舍前一个水管为front
代码: dfs(int x,int y,int front)//x,y为当前格子的坐标
front 为进水口的方向1 2 3 4分别为 左 上 右 下
2
1 ✟ 3
4
当当前的水管为直管:if(front==1) //进水口在左边
dfs(x,y+1,1)
if(front==2) //进水口在上边
dfs(x+1,y,2)
if(front==3) //进水口在右边
dfs(x,y-1,3)
if(front==4) //进水口在下边
dfs(x-1,y,4)
这个代码直接用 数组来表示会比较好 下面的代码会简化
当水管是弯管时
if(front==1) //进水口在左边
{
dfs(x+1,y,2) //3号的状态
dfs(x-1,y,4) //4号的状态
}
if(front==2) //进水口在左边
{
dfs(x,y+1,1) //1号的状态
dfs(x,y-1,3) //4号的状态
}
if(front==3) //进水口在左边
{
dfs(x-1,y,4) //1号的状态
dfs(x+1,y,2) //2号的状态
}
if(front==4) //进水口在左边
{
dfs(x,y+1,1) //2号的状态
dfs(x,y-1,3) //3号的状态
}
*/
下面是改进后的代码,挺好玩:
Windows版 C:
# include <stdio.h>
# include <stdlib.h>
# include <windows.h>
# include <time.h>
# define N 14 //地图的行数
# define M 16 //地图的列数
int Flag=0,BOOK[N+1][M+1]={0},S[N+2][M+2]={0},top=0,SUM=0,K,MAX[2];
const int NEXT[][2]={{0,0},{0,1},{1,0},{0,-1},{-1,0}};//用数组代替上面的判断
const int A[][3]={{0,0,0},{1,0,2},{0,1,1},{-1,0,4},{0,1,1}};//同上
const int B[][3]={{0,0,0},{-1,0,4},{0,-1,3},{1,0,2},{0,-1,3}};//同上
const char G[][3]={"▲","┗","┏","┓","┛","━","┃","进","出"};//数字对应的水管形状 或树木
const int T[][2]={{1,2},{4,3},{3,2},{4,1},{2,3},{1,4},{2,1},{3,4},{1,1},{3,3},{2,2},{4,4}};//弯的水管的进出方向1 2 3 4分别为 左 上 右 下
//const char Q[][3]={"┓","┓","┎","┎","┛","┛","┗","┗","━","━","┃","┃"};
const int LL[]={3,3,2,2,4,4,1,1,5,5,6,6};//可以用■ 代替上面的 G数组中的▲
char stack[M*N][3]={0}; //用二维数组模拟栈
void dfs(int X,int Y,int front);
int print(int num);
int main(){
int i,j;
do{
printf("输出路径坐标请按1 否则按0:");
scanf("%d",&K);
while(getchar()!='\n');
}while(K<0||K>1);
do{
S[1][0]=7;S[N][M+1]=8;
printf("原水管分布图:");
srand(time(NULL));//产生随机种子
for(i=0;i<=N+1;i++) //输出地图
{
printf("\n");
for(j=0;j<=M+1;j++)
{
if(i&&j&&i!=N+1&&j!=M+1)
S[i][j]=rand()%7;
printf("%s",G[S[i][j]]);
}
}
printf("\n");
dfs(1,1,1); //深度遍历
printf("当前地图%s能接通!\n",Flag?"\0":"不");
if(Flag)
{
printf("共%d种连接方式,已全显示 向上翻\n",SUM);
printf("最大步数%d 是第%d种\n",MAX[0],MAX[1]);
system("pause");
}
else
{
Sleep(1200);
system("cls");
}
}while(!Flag);
return 0;
}
int print(int num)
{
int i;
for(i=0;i<12;i++) // 2 // 1 3
if(stack[num][2]==T[i][0]&&stack[num+1][2]==T[i][1])
return LL[i]; //输出Q对应的水管形状
return -1;
}
void dfs(int X,int Y,int front)
{
int i,j;
if(X==N&&Y==M+1)//如果方案找到 输出 信息
{
stack[top+1][2]=1;
for(Flag=1;Flag<=top;Flag++) //输出路径坐标
{
if(K)
printf("(%2d,%2d)\t",stack[Flag][0],stack[Flag][1]);
S[stack[Flag][0]][stack[Flag][1]]=print(Flag);
}
printf("\n连接好之后[左上<入口>->右下<出口>]第%d种:\n共%d步\n",++SUM,top);
if(top>=MAX[0])
{
MAX[0]=top;
MAX[1]=SUM;
}
for(i=0;i<=N+1;i++)
{
for(j=0;j<=M+1;j++)
printf("%s",G[S[i][j]]);
printf("\n");
}
return ;
}
if(X<1||Y<1||X>N||Y>M||BOOK[X][Y])
return ;
BOOK[X][Y]=1;
stack[++top][0]=X;
stack[top][1]=Y;
if(S[X][Y]>=5&&S[X][Y]<=6)
{
stack[top][2]=front;
dfs(X+NEXT[front][0],Y+NEXT[front][1],front);//在上一个程序里有解释
}
if(S[X][Y]>=1&&S[X][Y]<=4)
{
stack[top][2]=front;
dfs(X+A[front][0],Y+A[front][1],A[front][2]);//在上一个程序里有解释
dfs(X+B[front][0],Y+B[front][1],B[front][2]);
}
BOOK[X][Y]=0;//消除当前坐标的标记
top--; //将当前坐标出栈
return ;
}
手机的C4droid版本 TCC:
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <time.h>
# define N 14 //地图的行数
# define M 16 //地图的列数
int Flag=0,BOOK[N+1][M+1]={0},S[N+2][M+2]={0},top=0,SUM=0,K,MAX[2];
const int NEXT[][2]={{0,0},{0,1},{1,0},{0,-1},{-1,0}};//用数组代替上面的判断
const int A[][3]={{0,0,0},{1,0,2},{0,1,1},{-1,0,4},{0,1,1}};//同上
const int B[][3]={{0,0,0},{-1,0,4},{0,-1,3},{1,0,2},{0,-1,3}};//同上
const char G[][4]={"♡","┗","┏","┓","┛","━","┃","♡","♡"};//数字对应的水管形状 或树木
const int T[][2]={{1,2},{4,3},{3,2},{4,1},{2,3},{1,4},{2,1},{3,4},{1,1},{3,3},{2,2},{4,4}};//弯的水管的进出方向1 2 3 4分别为 左 上 右 下
//const char Q[][3]={"┓","┓","┎","┎","┛","┛","┗","┗","━","━","┃","┃"};
const int LL[]={3,3,2,2,4,4,1,1,5,5,6,6};//可以用■ 代替上面的 G数组中的■ ▲
char stack[M*N][3]={0}; //用二维数组模拟栈
void dfs(int X,int Y,int front);
int print(int num);
int main(){
int i,j;
do{
printf("输出路径坐标请按1 否则按0:");
scanf("%d",&K);
while(getchar()!='\n');
}while(K<0||K>1);
do{
S[1][0]=7;S[N][M+1]=8;
printf("原水管分布图:");
srand(time(NULL));//产生随机种子
for(i=0;i<=N+1;i++) //输出地图
{
printf("\n");
for(j=0;j<=M+1;j++)
{
if(i&&j&&i!=N+1&&j!=M+1)
S[i][j]=rand()%7;
printf("%s",G[S[i][j]]);
}
}
printf("\n");
dfs(1,1,1); //深度遍历
printf("当前地图%s能接通!\n",Flag?"\0":"不");
if(Flag)
{
printf("共%d种连接方式,已全显示 向上翻\n",SUM);
printf("最大步数%d 是第%d种\n请按任意键继续……",MAX[0],MAX[1]);
getchar();
}
else
{
sleep(1);
system("clear");
}
}while(!Flag);
return 0;
}
int print(int num)
{
int i;
for(i=0;i<12;i++) // 2 // 1 3
if(stack[num][2]==T[i][0]&&stack[num+1][2]==T[i][1])
return LL[i]; //输出Q对应的水管形状
return -1;
}
void dfs(int X,int Y,int front)
{
int i,j;
if(X==N&&Y==M+1)//如果方案找到 输出 信息
{
stack[top+1][2]=1;
for(Flag=1;Flag<=top;Flag++) //输出路径坐标
{
if(K)
printf("(%2d,%2d)\t",stack[Flag][0],stack[Flag][1]);
S[stack[Flag][0]][stack[Flag][1]]=print(Flag);
}
printf("\n连接好之后[左上<入口>->右下<出口>]第%d种:\n共%d步\n",++SUM,top);
if(top>=MAX[0])
{
MAX[0]=top;
MAX[1]=SUM;
}
for(i=0;i<=N+1;i++)
{
for(j=0;j<=M+1;j++)
printf("%s",G[S[i][j]]);
printf("\n");
}
return ;
}
if(X<1||Y<1||X>N||Y>M||BOOK[X][Y])
return ;
BOOK[X][Y]=1;
stack[++top][0]=X;
stack[top][1]=Y;
if(S[X][Y]>=5&&S[X][Y]<=6)
{
stack[top][2]=front;
dfs(X+NEXT[front][0],Y+NEXT[front][1],front);//在上一个程序里有解释
}
if(S[X][Y]>=1&&S[X][Y]<=4)
{
stack[top][2]=front;
dfs(X+A[front][0],Y+A[front][1],A[front][2]);//在上一个程序里有解释
dfs(X+B[front][0],Y+B[front][1],B[front][2]);
}
BOOK[X][Y]=0;//消除当前坐标的标记
top--; //将当前坐标出栈
return ;
}
VM ubuntu 版
GCC
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <time.h>
# define N 14 //地图的行数
# define M 26 //地图的列数
int Flag=0,BOOK[N+1][M+1]={0},S[N+2][M+2]={0},top=0,SUM=0,K,MAX[2];
const int NEXT[][2]={{0,0},{0,1},{1,0},{0,-1},{-1,0}};//用数组代替上面的判断
const int A[][3]={{0,0,0},{1,0,2},{0,1,1},{-1,0,4},{0,1,1}};//同上
const int B[][3]={{0,0,0},{-1,0,4},{0,-1,3},{1,0,2},{0,-1,3}};//同上
const char G[][5]={"▲","┗","┏","┓","┛","━","┃","★","★"};//数字对应的水管形状 或树木
const int T[][2]={{1,2},{4,3},{3,2},{4,1},{2,3},{1,4},{2,1},{3,4},{1,1},{3,3},{2,2},{4,4}};//弯的水管的进出方向1 2 3 4分别为 左 上 右 下
//const char Q[][3]={"┓","┓","┎","┎","┛","┛","┗","┗","━","━","┃","┃"};
const int LL[]={3,3,2,2,4,4,1,1,5,5,6,6};//可以用■ 代替上面的 G数组中的▲
char stack[M*N][3]={0}; //用二维数组模拟栈
void dfs(int X,int Y,int front);
int print(int num);
int main(){
int i,j;
do{
printf("输出路径坐标请按1 否则按0:");
scanf("%d",&K);
while(getchar()!='\n');
}while(K<0||K>1);
do{
S[1][0]=7;S[N][M+1]=8;
printf("原水管分布图:");
srand(time(NULL));//产生随机种子
for(i=0;i<=N+1;i++) //输出地图
{
printf("\n");
for(j=0;j<=M+1;j++)
{
if(i&&j&&i!=N+1&&j!=M+1)
S[i][j]=rand()%7;
printf("%s",G[S[i][j]]);
}
}
printf("\n");
dfs(1,1,1); //深度遍历
printf("当前地图%s能接通!\n",Flag?"\0":"不");
if(Flag)
{
printf("共%d种连接方式,已全显示 向上翻\n",SUM);
printf("最大步数%d 是第%d种\n",MAX[0],MAX[1]);
//pause();
getchar();
}
else
{
sleep(1);
system("clear");
}
}while(!Flag);
return 0;
}
int print(int num)
{
int i;
for(i=0;i<12;i++) // 2 // 1 3
if(stack[num][2]==T[i][0]&&stack[num+1][2]==T[i][1])
return LL[i]; //输出Q对应的水管形状
return -1;
}
void dfs(int X,int Y,int front)
{
int i,j;
if(X==N&&Y==M+1)//如果方案找到 输出 信息
{
stack[top+1][2]=1;
for(Flag=1;Flag<=top;Flag++) //输出路径坐标
{
if(K)
printf("(%2d,%2d)\t",stack[Flag][0],stack[Flag][1]);
S[stack[Flag][0]][stack[Flag][1]]=print(Flag);
}
printf("\n连接好之后[左上<入口>->右下<出口>]第%d种:\n共%d步\n",++SUM,top);
if(top>=MAX[0])
{
MAX[0]=top;
MAX[1]=SUM;
}
for(i=0;i<=N+1;i++)
{
for(j=0;j<=M+1;j++)
printf("%s",G[S[i][j]]);
printf("\n");
}
return ;
}
if(X<1||Y<1||X>N||Y>M||BOOK[X][Y])
return ;
BOOK[X][Y]=1;
stack[++top][0]=X;
stack[top][1]=Y;
if(S[X][Y]>=5&&S[X][Y]<=6)
{
stack[top][2]=front;
dfs(X+NEXT[front][0],Y+NEXT[front][1],front);//在上一个程序里有解释
}
if(S[X][Y]>=1&&S[X][Y]<=4)
{
stack[top][2]=front;
dfs(X+A[front][0],Y+A[front][1],A[front][2]);//在上一个程序里有解释
dfs(X+B[front][0],Y+B[front][1],B[front][2]);
}
BOOK[X][Y]=0;//消除当前坐标的标记
top--; //将当前坐标出栈
return ;
}