【算法】矩阵填数,深度优先搜索(DFS),Pascal改C语言
面向对象的上机实验
题目
以下列方式向 5*5 矩阵中填入数字。设数字i(1=<i<=25),则数字i+1 的坐标位置应为(E, W)。(E, W)可根据下列关系由(x,y)算出:
1)(E, W)=(x±3,y)
2)(E, W)=(x,y±3)
3)(E, W)=(x±2,y±2)
求解问题如下:
编写一个程序,当数字1被指定于某个起始位置时,列举出其它24个数字应在的位置;列举该条件下的所有可能方案。
参考答案
网上搜索到数学奥赛中本题的Pascal代码
来自http://blog.sina.com.cn/s/blog_1317189490102vp1k.html
Program lx9_1_3;
uses crt;
const n=5;
d:array[1..8,1..2] of shortint=((3,0),(-3,0),(0,3),(0,-3),
(2,2),(2,-2),(-2,2),(-2,-2));
var x0,y0:byte;
a:array[1..n,1..n] of byte;
total:longint;
procedure print;
var i,j:integer;
begin
inc(total);
gotoxy(1,3);
writeln(‘[‘,total,‘]‘);
for i:=1 to n do
begin
for j:=1 to n do
write(a[i,j]:3);
writeln;
end;
end;
procedure try(x,y,k:byte);
var i,x1,y1:integer;
begin
for i:=1 to 8 do
begin
x1:=x+d[i,1];y1:=y+d[i,2];
if (x1>0) and (y1>0) and (x1<=n)
and (y1<=n) and (a[x1,y1]=0) then
begin
a[x1,y1]:=k;
if k=n*n then print
else try(x1,y1,k+1);
a[x1,y1]:=0;
end;
end;
end;
begin
clrscr;
write(‘x0,y0=‘);readln(x0,y0);
fillchar(a,sizeof(a),0);
total:=0;a[x0,y0]:=1;
try(x0,y0,2);
writeln(‘Total=‘,total);
writeln(‘Press any key to exit..。‘);
repeat until keypressed;
end.自改C语言代码
运用了深度优先搜索算法。
可以输入一个起始位置的坐标后,列举出所有可能方案和方案个数。
也可以输出所有初始点方案的个数。
#include <stdio.h>
#define N 5//格子行列数
int next[8][2]={{3,0},{-3,0},{0,3},{0,-3},{2,2},{2,-2},{-2,2},{-2,-2}};//下一步变换的位移
int x0,y0;//输入的初始坐标
int matrix[N][N];//存储nxn矩阵中的数字
int total;//方案数量
//打印一个矩阵的函数
void printMatrix(){
int i,j;
total+=1;//出来一次结果,就打印一次,方案数+1
printf("第%d种方案:\n",total);
for(i=0;i<N;i++){
for(j=0;j<N;j++){
printf("%4d",matrix[i][j]);//%4d表示输出宽度为4,且右对齐
}
printf("\n");
}
printf("\n");
}
////每个初始点都输出方案的个数的话就不把每个方案打印出来了,太占地方
//void printMatrix(){
// int i,j;
// total+=1;//出来一次结果,就打印一次,方案+1
//}
//主要函数,(x,y)是矩阵内坐标,k是第几个数字
void try(x,y,k){
int i,x1,y1;//x1,y1是本次要找的坐标
//将8个位移都试一遍
for(i=0;i<8;i++){
x1=x+next[i][0];
y1=y+next[i][1];
//如果该位置不超过边界且没有数字,则方案可行,把数字装进这个位置
if((x1>-1)&&(y1>-1)&&(x1<N)&&(y1<N)&&(matrix[x1][y1]==0)){
matrix[x1][y1]=k;
//如果k=25即已经搜索完,可以打印了
if(k==N*N)
printMatrix();
//如果还没到25,就继续搜索下一个位置
else
try(x1,y1,k+1);
//本次打印完/本次搜索尝试到死路,回溯到上一节点去往另一分支前,将这一节点清零
matrix[x1][y1]=0;
}
}
}
int main()
{
//输入坐标
printf("请输入第一个数的坐标(逗号间隔):");
scanf("%d,%d",&x0,&y0);
//矩阵整体清0(第一条在dev-c++可以跑,vc++不行,还是用老办法)
//memset(matrix, 0, sizeof(matrix));
int i,j;
for(i=0;i<N;i++){
for(j=0;j<N;j++){
matrix[i][j]=0;
}
}
//数据初始化,运行
total=0;//方案数为零
x0-=1;y0-=1;//用户输入坐标从1开始,c语言数组从0开始
matrix[x0][y0]=1;//第一个位置赋值1
try(x0,y0,2); //从数字2开始放置
printf("总共有%d种摆放方案\n\n",total);
// //每个初始点都输出方案的个数
// int m,n;
// for(m=0;m<5;m++){
// for(n=0;n<5;n++){
// x0=m;y0=n;
// //矩阵整体清0
// int i,j;
// for(i=0;i<N;i++){
// for(j=0;j<N;j++){
// matrix[i][j]=0;
// }
// }
// total=0;//每次节点前方案数清零
// matrix[x0][y0]=1;//第一个位置赋值1
// try(x0,y0,2); //从数字2开始放置
// printf("数字1被指定于(%d,%d)有%d种方案\n",m+1,n+1,total);
// }
// printf("\n");//每5行之后打个空行好看点
// }
}结果
- 输入一个起始点坐标后输出的方案


- 输出所有起始点的方案个数:
