| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3203 人关注过本帖
标题:[求助]八皇后问题的12组实质解怎么求解?~~
只看楼主 加入收藏
boaq1986
Rank: 1
等 级:新手上路
帖 子:1
专家分:0
注 册:2006-5-21
收藏
 问题点数:0 回复次数:4 
[求助]八皇后问题的12组实质解怎么求解?~~

是作业题~~做了好久都不对,要求是根据给出的求八皇后全部92组解的程序修改成求12组实质解的程序.我编完之后输出了27个..................而且好象在main函数里多执行check几次的话解的数目还会无限制地变小..........狂汗ing...........
(因为是修改的哈,那个a[92][9]和loca[N]之间的转换以及checkid[92]都是看起来怪怪的.....打算先把程序修改得能正确输出12个解的时候再改善这个部分.....汗)

#include <math.h>
#include <stdio.h>
#include <conio.h>
#define N 8
int local[N],a[92][9],count=0,count1=1,checkid[92];
void trans_result(int count){
int i;
for(i=0; i<N; i++){
a[count][i+1]=local[i]+1;
}
}
int check_cross(int n){
int i;
for (i=0; i<n; i++){
if (local[i] == local[n] || (n-i) == abs(local[i]-local[n]))
return 1;
}
return 0;
}
void put_chess(int n){
int i;
for (i=0; i<N; i++){
local[n] = i;
if (!check_cross(n)){
if (n == N-1) {
trans_result(count);
count++;
}
else put_chess(n+1);
}
}
}
void result(){
int i,j;
for(i=1;i<=91;i++){
if(a[i][0]==0){
if(count1<10)
printf("Solution[0%d]: ",count1);
else
printf("Solution[%d]: ",count1);
for(j=1; j<9; j++){
printf("%d ",a[i][j]);
}
printf("\n");
count1++;
}
}
}
void check_1(){//关于水平线对称
int i=0,j,k,flag=0;
for(i=0;i<=91;i++){
for(j=i+1;j<=91;j++){
flag=0;
if(a[j][0]==0){
for(k=1;k<=9;k++){
if(a[i][k]+a[j][k]==9){
flag++;
}
}
if(flag==8){
a[j][0]=1;
checkid[j]=1;
}
}
}
}
}
void check_2(){//关于竖直线对称
int i,j,k,flag=0;
for(i=0;i<=91;i++){
for(j=i+1;j<=91;j++){
flag=0;
if(a[j][0]==0){
for(k=1;k<9;k++){
if(a[i][k]==a[j][9-k]){
flag++;
}
}
if(flag==8){
a[j][0]=1;
checkid[j]=1;
}
}
}
}
}
void check_3(){//关于主对角线对称
int i,j,k,flag=0;
for(i=0;i<=91;i++){
for(j=i+1;j<=91;j++){
flag=0;
if(a[j][0]==0){
for(k=1;k<9;k++){
if(a[j][(a[i][k])]==k){
flag++;
}
}
if(flag==8){
a[j][0]=1;
checkid[j]=1;
}
}
}
}
for(i=0;i<=91;i++)
a[i][0]=0;
}
void check_4(){//关于从对角线对称
int i,j,k,flag=0;
for(i=0;i<=91;i++){
for(j=i+1;j<=91;j++){
if(a[j][0]==0){
for(k=1;k<9;k++){
if(a[j][(8-a[i][k])]==8-k){
flag++;
}
}
if(flag==8){
a[j][0]=1;
checkid[j]=1;
}
}
}
}
}
void check(){
int i;
check_1();
for(i=0;i<=91;i++){
a[i][0]=0;
}
check_2();
for(i=0;i<=91;i++){
a[i][0]=0;
}
check_3();
for(i=0;i<=91;i++){
a[i][0]=0;
}
check_4();
for(i=0;i<=91;i++){
a[i][0]=checkid[i];
}
result();
}
void main(){
put_chess(0);
check();
}


[此贴子已经被作者于2006-5-21 3:06:21编辑过]

搜索更多相关主题的帖子: 皇后 实质 求解 
2006-05-21 03:03
–★–
Rank: 3Rank: 3
等 级:新手上路
威 望:6
帖 子:1512
专家分:0
注 册:2006-5-1
收藏
得分:0 

【例6-51】枚举法求解八皇后问题。

【分析】承上题,仍用诸如{1,5,8,6,3,7,2,4}这样的数列表示八皇后问题的解,不难看出,这恰好是数字1~8的一种全排列。事实上,如果缺某数或某数不止1次地出现,就肯定不是八皇后问题的解。例如{1,5,8,6,3,7,2,5}缺4而5出现两次,相当于棋盘的第4列上什么棋子也没有,第5列上却有两个皇后!注意1~8全排列只是解的必要条件,尚待斜线条件(即沿±45°斜线只有0~1个皇后)作进一步甄别。甄别函数OK()根据斜线条件判断是否八皇后问题的解。在-45°即沿主对角线方向,斜线条件表现为皇后所在行、列号之差的绝对值必须惟一;在+45°即沿副对角线方向,斜线条件表现为皇后所在行、列号之和必须惟一。程序清单如下

/* ex6-51.c或8queen.c */

#include<stdio.h>

#define N 8 /*皇后数*/

typedef int bool;

main( )

{ int NSOLVE=0; char solve[ ]="???????? ";

int s[N]={1,2,3,4,5,6,7,8},a,b,c,d,e,f,g,h;

int t[N]={1,1,1,1,1,1,1,1}; /*对应元素的忙闲信息,此处规定1:未用; 0:已用*/

for(a=0; a<N; a++)

{ t[a]=0; solve[0]=s[a]+'0';

for(b=0; b<N; b++)if(t[b])

{ t[b]=0; solve[1]=s[b]+'0';

for(c=0; c<N; c++)if(t[c])

{ t[c]=0; solve[2]=s[c]+'0';

for(d=0; d<N; d++)if(t[d])

{ t[d]=0; solve[3]=s[d]+'0';

for(e=0; e<N; e++)if(t[e])

{ t[e]=0; solve[4]=s[e]+'0';

for(f=0; f<N; f++)if(t[f])

{ t[f]=0; solve[5]=s[f]+'0';

for(g=0; g<N; g++)if(t[g])

{ t[g]=0; solve[6]=s[g]+'0';

for(h=0; h<N; h++)if(t[h])

{ t[h]=0; solve[7]=s[h]+'0';

if(OK(solve))

{ printf("%s",solve);

if(++NSOLVE%8==0)printf("\n");

} t[h]=1;

} t[g]=1;

} t[f]=1;

} t[e]=1;

} t[d]=1;

} t[c]=1;

} t[b]=1;

} t[a]=1;

}

printf("\n八皇后问题共有%d个解.\n",NSOLVE);

}

bool OK(char slv[ ])

{ int i,j,sum,dif;

for(i=0; i<N; i++)

{ sum=i+slv[i]; dif=i-slv[i];

for(j=0; j<N; j++)if(j!=i)

{ if(j+slv[j]==sum)return(0);

if(j-slv[j]==dif)return(0);

}

}

return(1);

}

运行结果如下

15863724 16837425 17468253 17582463 24683175 25713864 25741863 26174835

26831475 27368514 27581463 28613574 31758246 35281746 35286471 35714286

35841726 36258174 36271485 36275184 36418572 36428571 36814752 36815724

36824175 37285146 37286415 38471625 41582736 41586372 42586137 42736815

42736851 42751863 42857136 42861357 46152837 46827135 46831752 47185263

47382516 47526138 47531682 48136275 48157263 48531726 51468273 51842736

51863724 52468317 52473861 52617483 52814736 53168247 53172864 53847162

57138642 57142863 57248136 57263148 57263184 57413862 58413627 58417263

61528374 62713584 62714853 63175824 63184275 63185247 63571428 63581427

63724815 63728514 63741825 64158273 64285713 64713528 64718253 68241753

71386425 72418536 72631485 73168524 73825164 74258136 74286135 75316824

82417536 82531746 83162574 84136275

八皇后问题共有92个解.

“横看成岭侧成峰”,八皇后问题的92个解实际上只有12组独立解。图6-2从基本解{1,5,8,6,3,7,2,4}(左上角)出发,沿水平方向相继绘出了(相对于基本解)逆时针旋转90、180、270度情况下得到的衍生解;下方的4幅图则是其正上方图行、列对调后的衍生解。

基本解 逆时针转90° 再逆时针转90° 再逆时针转90°

(15863724) (36428571) (57263148) (82417536)

■□□□□□□□ □□■□□□□□ □□□□■□□□ □□□□□□□■

□□□□■□□□ □□□□□■□□ □□□□□□■□ □■□□□□□□

□□□□□□□■ □□□■□□□□ □■□□□□□□ □□□■□□□□

□□□□□■□□ □■□□□□□□ □□□□□■□□ ■□□□□□□□

□□■□□□□□ □□□□□□□■ □□■□□□□□ □□□□□□■□

□□□□□□■□ □□□□■□□□ ■□□□□□□□ □□□□■□□□

□■□□□□□□ □□□□□□■□ □□□■□□□□ □□■□□□□□

□□□■□□□□ ■□□□□□□□ □□□□□□□■ □□□□□■□□

行列对调 行列对调 行列对调 行列对调

(17582463) (84136275) (63571428) (42736851)

■□□□□□□□ □□□□□□□■ □□□□□■□□ □□□■□□□□

□□□□□□■□ □□□■□□□□ □□■□□□□□ □■□□□□□□

□□□□■□□□ ■□□□□□□□ □□□□■□□□ □□□□□□■□

□□□□□□□■ □□■□□□□□ □□□□□□■□ □□■□□□□□

□■□□□□□□ □□□□□■□□ ■□□□□□□□ □□□□□■□□

□□□■□□□□ □■□□□□□□ □□□■□□□□ □□□□□□□■

□□□□□■□□ □□□□□□■□ □■□□□□□□ □□□□■□□□

□□■□□□□□ □□□□■□□□ □□□□□□□■ ■□□□□□□□

图6-2 基本解{1,5,8,6,3,7,2,4}及其衍生解

【例6-52】用枚举法找出八皇后问题的独立解。

【分析】如何实现行列对调和逆时针转90度是编程的关键。基本解{1,5,8,6,3,7,2,4}中的'1'代表第1行第1列即(1,1)处有皇后、'5'代表(2,5)处有皇后、……'4'代表(8,4)处有皇后;行列对调后变成(1,1)处、(5,2)处、……(4,8)处有皇后。因此下面的程序段

int i,s[8]={1,5,8,6,3,7,2,4},t[8]/*存放行列对调后的衍生解*/;

for(i=1; i<=8; i++)t[s[i-1]-1]=i;

可实现行列对调。观察逆时针转90度后棋盘(相对于基本解)的变化发现,原先位于(i,j)的皇后经旋转到达了(9-j,i)处,如原先的第4行第6列变成了第3行第4列。因此程序段

int i,s[8]={1,5,8,6,3,7,2,4},t[8]/*存放逆时针转90度的衍生解*/;

for(i=1; i<=8; i++)t[8-s[i-1]]=i;

可实现逆时针转90度。程序清单如下(沿用ex6-51.c的主函数)

/* ex6-52.fun */

#include<string.h>

bool OK(char slv[ ])

{ int i,j,sum,dif;

static char sos[100][N+2]; static num=0;

for(i=0; i<N; i++)

{ sum=i+slv[i]; dif=i-slv[i];

for(j=0; j<N; j++)if(j!=i)

{ if(j+slv[j]==sum)return(0);

if(j-slv[j]==dif||j-slv[j]==-dif)return(0);

}

}

if(num)/*如果sos数组已存有衍生解*/

for(i=0; i<num; i++)if(strcmp(slv,sos[i])==0)return(0);

rot(sos[num],slv); rot(sos[num+1],sos[num]); rot(sos[num+2],sos[num+1]);

zhuan(sos[num+3],slv); zhuan(sos[num+4],sos[num]);

zhuan(sos[num+5],sos[num+1]); zhuan(sos[num+6],sos[num+2]);

num+=7; return(1);

}

rot(char d[ ],char s[ ])

{ int i;

for(i=1; i<=N; i++)d[N-(s[i-1]-'0')]=i+'0'; d[N]=' ';

}

zhuan(char d[ ],char s[ ])

{ int i;

for(i=1; i<=N; i++)d[s[i-1]-'0'-1]=i+'0'; d[N]=' ';

}

运行结果如下

15863724 16837425 24683175 25713864 25741863 26174835 26831475 27368514

27581463 35281746 35841726 36258174

八皇后问题共有12个解. 这12组独立解如图6-3所示。

(15863724) (16837425) (24683175) (25713864)

■□□□□□□□ ■□□□□□□□ □■□□□□□□ □■□□□□□□

□□□□■□□□ □□□□□■□□ □□□■□□□□ □□□□■□□□

□□□□□□□■ □□□□□□□■ □□□□□■□□ □□□□□□■□

□□□□□■□□ □□■□□□□□ □□□□□□□■ ■□□□□□□□

□□■□□□□□ □□□□□□■□ □□■□□□□□ □□■□□□□□

□□□□□□■□ □□□■□□□□ ■□□□□□□□ □□□□□□□■

□■□□□□□□ □■□□□□□□ □□□□□□■□ □□□□□■□□

□□□■□□□□ □□□□■□□□ □□□□■□□□ □□□■□□□□

(25741863) (26174835) (26831475) (27368514)

□■□□□□□□ □■□□□□□□ □■□□□□□□ □■□□□□□□

□□□□■□□□ □□□□□■□□ □□□□□■□□ □□□□□□■□

□□□□□□■□ ■□□□□□□□ □□□□□□□■ □□■□□□□□

□□□■□□□□ □□□□□□■□ □□■□□□□□ □□□□□■□□

■□□□□□□□ □□□■□□□□ ■□□□□□□□ □□□□□□□■

□□□□□□□■ □□□□□□□■ □□□■□□□□ □□□□■□□□

□□□□□■□□ □□■□□□□□ □□□□□□■□ ■□□□□□□□

□□■□□□□□ □□□□■□□□ □□□□■□□□ □□□■□□□□

(27581463) (35281746) (35841726) (36258174)

□■□□□□□□ □□■□□□□□ □□■□□□□□ □□■□□□□□

□□□□□□■□ □□□□■□□□ □□□□■□□□ □□□□□■□□

□□□□■□□□ □■□□□□□□ □□□□□□□■ □■□□□□□□

□□□□□□□■ □□□□□□□■ □□□■□□□□ □□□□■□□□

■□□□□□□□ ■□□□□□□□ ■□□□□□□□ □□□□□□□■

□□□■□□□□ □□□□□□■□ □□□□□□■□ ■□□□□□□□

□□□□□■□□ □□□■□□□□ □■□□□□□□ □□□□□□■□

□□■□□□□□ □□□□□■□□ □□□□□■□□ □□□■□□□□

图6-3 八皇后问题的12组独立解

细心的读者可能想到,12组独立解+(12×7)个衍生解,总数似应为96,为什么ex6-51程序仅给出92个解呢?原因是第10组独立解{3,5,2,8,1,7,4,6}(参看图6-3)给出的棋局为中心对称图形,即旋转180°后形状不变。因此这组解实际上只能给出3个(而不是7个)不雷同的衍生解。八皇后问题解的个数可表示为11×8+1×4=92。


落霞与孤鹜齐飞,秋水共长天一色! 心有多大,路有多宽。三教九流,鸡鸣狗盗。兼收并蓄,海纳百川。
2006-05-21 08:16
–★–
Rank: 3Rank: 3
等 级:新手上路
威 望:6
帖 子:1512
专家分:0
注 册:2006-5-1
收藏
得分:0 
/*-------------------------------*
发一个纯粹的获得12个独立解的代码
*-------------------------------*/
#include<string.h>
#include<stdio.h>
#define N 8 /*皇后数*/
typedef int bool;
rot(char d[ ],char s[ ])
{ int i;
for(i=1; i<=N; i++)d[N-(s[i-1]-'0')]=i+'0'; d[N]=' ';
}
zhuan(char d[ ],char s[ ])
{ int i;
for(i=1; i<=N; i++)d[s[i-1]-'0'-1]=i+'0'; d[N]=' ';
}
bool OK(char slv[ ])
{ int i,j,sum,dif;
static char sos[100][N+2]; static num=0;
for(i=0; i<N; i++)
{ sum=i+slv[i]; dif=i-slv[i];
for(j=0; j<N; j++)if(j!=i)
{ if(j+slv[j]==sum)return(0);
if(j-slv[j]==dif||j-slv[j]==-dif)return(0);
}
}
if(num)/*如果sos数组已存有衍生解*/
for(i=0; i<num; i++)if(strcmp(slv,sos[i])==0)return(0);
rot(sos[num],slv); rot(sos[num+1],sos[num]); rot(sos[num+2],sos[num+1]);
zhuan(sos[num+3],slv); zhuan(sos[num+4],sos[num]);
zhuan(sos[num+5],sos[num+1]); zhuan(sos[num+6],sos[num+2]);
num+=7; return(1);
}
main( )
{ int NSOLVE=0; char solve[ ]="???????? ";
int s[N]={1,2,3,4,5,6,7,8},a,b,c,d,e,f,g,h;
int t[N]={1,1,1,1,1,1,1,1}; /*对应元素的忙闲信息,此处规定1:未用; 0:已用*/
for(a=0; a<N; a++)
{ t[a]=0; solve[0]=s[a]+'0';
for(b=0; b<N; b++)if(t[b])
{ t[b]=0; solve[1]=s[b]+'0';
for(c=0; c<N; c++)if(t[c])
{ t[c]=0; solve[2]=s[c]+'0';
for(d=0; d<N; d++)if(t[d])
{ t[d]=0; solve[3]=s[d]+'0';
for(e=0; e<N; e++)if(t[e])
{ t[e]=0; solve[4]=s[e]+'0';
for(f=0; f<N; f++)if(t[f])
{ t[f]=0; solve[5]=s[f]+'0';
for(g=0; g<N; g++)if(t[g])
{ t[g]=0; solve[6]=s[g]+'0';
for(h=0; h<N; h++)if(t[h])
{ t[h]=0; solve[7]=s[h]+'0';
if(OK(solve))
{ printf("%s",solve);
if(++NSOLVE%8==0)printf("\n");
} t[h]=1;
} t[g]=1;
} t[f]=1;
} t[e]=1;
} t[d]=1;
} t[c]=1;
} t[b]=1;
} t[a]=1;
}
printf("\n八皇后问题共有%d个独立解.\n",NSOLVE);
}
/*
运行结果如下
15863724 16837425 24683175 25713864 25741863 26174835 26831475 27368514 27581463 35281746 35841726 36258174
*/

落霞与孤鹜齐飞,秋水共长天一色! 心有多大,路有多宽。三教九流,鸡鸣狗盗。兼收并蓄,海纳百川。
2006-05-21 09:24
vaxyne
Rank: 1
等 级:新手上路
帖 子:3
专家分:0
注 册:2006-5-16
收藏
得分:0 

还差将其旋转90度,180度,270度的对称,再把这3种删减下去就够了

2006-05-23 10:30
–★–
Rank: 3Rank: 3
等 级:新手上路
威 望:6
帖 子:1512
专家分:0
注 册:2006-5-1
收藏
得分:0 
回复:(vaxyne)还差将其旋转90度,180度,270度的对称...
以下是引用vaxyne在2006-5-23 10:30:00的发言:

还差将其旋转90度,180度,270度的对称,再把这3种删减下去就够了

朋友,已经是12个独立解了,还删什么呀?信口雌黄可不好。
如不服气,可指出哪两、三个是线性相关的。好吗?


落霞与孤鹜齐飞,秋水共长天一色! 心有多大,路有多宽。三教九流,鸡鸣狗盗。兼收并蓄,海纳百川。
2006-05-23 16:59
快速回复:[求助]八皇后问题的12组实质解怎么求解?~~
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.053178 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved