回 帖 发 新 帖 刷新版面

主题:[原创]概率算法—n皇后问题拉斯维加斯算法优化

最近心情不好,离开论坛一段时间。最后给大家贴个以前编的程序,n皇后问题的概率解法。

【问题】
在n*n的棋盘上,放上n个皇后,按国际象棋规则,没有任何两个皇后会互相攻击。

【要求】
打印出其中一种摆放的方法。
考虑n较大时(例如n=100)时程序得到答案的速度问题。


【程序所用的算法提示】
1、拉斯维加斯概率算法
每一行得到了几个摆放位置时,不是按顺序进行摆放,而是随机摆放的。因此程序每次运行的时间都不一样。用拉斯维加斯算法除非找不到解,如果找到,答案就一定是正确的。

2、优化算法
这是我修改的算法。标准拉斯维加斯算法的特点是:当无法继续往下摆放时,就从头重新开始。我修改后的方法是:类似回溯,但实际上是“伪回溯”。无论在哪一行受阻无法摆放,第1次受阻后退1行继续摆;第2次受阻后退2行继续摆;依此类推。

回复列表 (共7个回复)

沙发

【源程序】

(*
    One Answer Of N Queens Problem.
    Arithmetic Of j.t.Chang's LV.
*)

program LV_Queens;
uses crt,dos;
const
     M=10000;

var
    x:array[1..M] of integer;
    i:integer;

    h1,m1,s1,hund1,
    h2,m2,s2,hund2:word;
    N: integer;

procedure PrintResult;
var
    i,j: integer;
    t1,t2:longint;
    f:text;
    ch: char;
begin
    gettime(h2,m2,s2,hund2);
    if (h2<h1) then h2:=h2+24;
    t1:=1;  t2:=1;
    t1:=t1*s1*100+t1*m1*60*100+t1*h1*3600*100+hund1;
    t2:=t2*s2*100+t2*m2*60*100+t2*h2*3600*100+hund2;
    t1:=t2-t1;
    hund1:=t1 mod 100;   t1:=t1 div 100;
    s1:=t1 mod 60;       t1:=t1 div 60;
    m1:=t1 mod 60;       t1:=t1 div 60;
    h1:=t1;              writeln;
    write('One answer found.   Used time: ');
    write(h1 div 10, h1 mod 10, ':');
    write(m1 div 10, m1 mod 10, ':');
    write(s1 div 10, s1 mod 10, '.');
    writeln(hund1 div 10,hund1 mod 10);
    write('Press any key to view result... ');
    ch:=readkey;  writeln;
    for i:=1 to N do
      begin
         for j:=1 to N do
           if j=x[i] then write ('Q':2)
             else write('.':2) ;
         writeln;
      end;
    writeln;
    for i:=1 to N do write(x[i]:5);
    writeln;  writeln;
    write('Save result to file (y/n)? ');
    ch:=readkey;   writeln(ch);
    if upcase(ch)='Y' then
      begin
          assign(f,'QUEENS.TXT');
          rewrite(f);
          writeln(f,'One answer of ',N,' queens problem: ');
          writeln(f);
          for i:=1 to N do
             begin
                  write(f,x[i]:5);
                  if i mod 16=0 then writeln(f);
             end;
          writeln(f);
          close(f);
          writeln('Result save to file: QUEENS.TXT');
      end;
end;

function place(k,a:integer):boolean;
var
    i:integer;
begin
   for i:=1 to k-1 do
      if (k-i)=abs(a-x[i])  then
        begin
            place:=false;
            exit;
        end;
   place:=true;
end;

procedure  queensLV;
var
    i,j,k,c,t,stop: integer;

begin
   for i:=1 to N do x[i]:=i;
   k:=1; c:=1;  stop:=1;
   randomize;
   while  (k<=N)  do
     begin
         c:=0;
         for j:=k to N do
           if place(k,x[j]) then
             begin
                 c:=c+1;
                 if random(c)=0 then t:=j;
             end;
         if c>0 then
           begin
               if(t<>k) then
                 begin
                     x[k]:=x[k] xor x[t];
                     x[t]:=x[t] xor x[k];
                     x[k]:=x[k] xor x[t];
                 end;
               k:=k+1;
           end
             else
               begin
                  k:=k-stop;
                  stop:=stop+1;
                  if k<1 then
                    begin
                        k:=1;
                        stop:=1;
                    end;
               end;
     end;
end;

begin
     clrscr;
     writeln;
     writeln('N Queens Problem.');
     writeln('Programmed by j.t.Chang.');
     writeln;
     write('Enter N (N>=4): '); readln(N);
     if (N<4) or (N>M) then
        begin
            writeln('Out of range: 4..',M);
            halt;
        end;
     writeln('Finding one answer of ',N,' queens problem.');
     writeln('Please wait...');
     gettime(h1,m1,s1,hund1);
     for  i:=1 to N do x[i]:=0;
     queensLV;
     PrintResult;
end.

板凳

恩恩恩
8错
值得学习!!比如那个伪回溯。

3 楼

我不明白
为什么要那样回溯呢?

4 楼

若要

5 楼

求所有解是否会数据太大? 

6 楼

贴个c++语言版的 
#include <iostream>
#include <ctime>
#include <cmath>//in vc 6.0 
using namespace std;
const int n=8;
int t=3;
int x[n+1];//don't use x[0]
int bestx[n+1];//don't use bestx[0]
long sum=0;
bool Place(int k)
{
    for(int j=1;j<k;j++)
    {
        if(abs(k-j)==abs(x[k]-x[j]) || x[j]==x[k])//不符合条件 返回假
            return false;
    }
    return true;    
}

int Rand(int m)
{
    srand((unsigned) time(NULL));
    return rand()%m;
}
bool Queenslv(int stop)
{
    int k=1;
    int count=1;
    while((k<stop) && (count>0))
    {
        count=0;
        int j=0;
        for(int i=0;i<n;i++)
        {
            x[k]=i;
            if(Place(k))
                if(Rand(++count)==0)
                    j=i;
        }
        if(count>0)
            x[k++]=j;
    }
    return (count>0);
}

void QueenTB(int t)
{
    if(t>n)
    {
        sum++;
        for(int j=1;j<=n;j++)//更新记录,输出
        {
            bestx[j]=x[j];
            cout<<bestx[j]<<"\t";
        }
        cout<<endl;
    }
    else
    {
        for(int i=1;i<=n;i++)
        {
            x[t]=i;
            if(Place(t))QueenTB(t+1);
        }
    }
}
void Nqueen()
{
    int stop=3;
    while(!Queenslv(stop));
    QueenTB(stop);
//    {
//        for(int i=0;i<n;i++)
//            cout<<bestx[i]<<"\t";
//        cout<<endl;
//    }
}

int main()
{
//    QueenTB(t);
    Nqueen();
    cout<<sum;
    cout<<endl;
    return 0;
}

7 楼

stop越大,得到结果的概率越小
取7、8时要多试几次,有的解也很少,这时效率并不好
一般取3比较好

我来回复

您尚未登录,请登录后再回复。点此登录或注册