The BackTracking algorithm for n queen problem
2005-04-06 00:55
393 查看
The article is about the design of algorithm for n queen problem. The intention of this article is from an excise of an algorithm book: <<Introduction to the design and analysis of algorithms>>. This backtracking algorithm is interesting, so I decide to record the process of implementation. First, I use a double dimension array to simulate the chess board. But quickly I have found this form of representation is not so convenient especially in the check function that is used to checking whether or not current solution is promising. Because the check function is worked with the index of array, the value of array is trivial. i.e. a[0][0] = 1 represent (0,0) position of chess board has a chess and the next chess can't be position (0,1) and (0,0). The pair (0,0) already indicate position (0,0) has a chess, it is unnecessary to assigning a value 1 to pair (0,0) to denoting (0,0) has chess. So I have changed a representation of chess position by vector<pair<int,int> >. Apparently, pair<int, int> stands for (x,y). Notice that a solution of n queen require each row is different. That is, for a solution of n queen, each of pair_instance.first must distinct. This simplifies the representation further. It just needs a vector<int> to represent a chess board. So the solution of n queen problem can be viewed as a permutation of natural number from 0 to n-1. Apparently, the brute-force algorithm has efficiency Ω(n!).
For the part of check function, I have observed the characteristic of permutation that is confirmed with n queen problem. The rule is defined as follow:
If the number of position p in permutation is i, then the vaule of position q(denoted by j) can't be q-p+i or p-q+i.(q∈(p,n-1] );
REVIST: (0,0)(1,2)(2,4)(3,3)(4,1) is a illegal solution which can be viewed as 0,2,4,3,1simply. 4(i) in position 2(p), 3(q's vaule: j) in position 3(q) ------ q-p+i = 5(no violation); p-q+i = 3(violation). (starting from zero))
It requires a two nested for loop to attaining. In addition, if there exist a method to constructing a NFA to recognize the permutation, the n queen problem algorithm will have Θ(n) efficiency class. But it seems impossible to do that because the FA needs counting and no way to abstract states.
The codes:
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <functional>
#include <ctime>
using namespace std;
template<class T>
struct output_functor : public unary_function<T,void>
{
void operator()(const T& p)const
{
cout<<"("<<p.first<<","<<p.second<<")"<<" ";
}
};
class chess_board
{
vector<pair<int, int> > position;
vector<int> array;
vector<int> duplicate_array;
public:
int n;
int cur_i;
int number_solution;
chess_board(int dim):n(dim),cur_i(0),number_solution(0)
{
position.reserve(n);
array.resize(n,-30000);//if using -1 to denoting no chess, it will contradict with the diagonal test. i.e. move{0,0}.the content of array is {0,-1,-1,-1}.the diagonal test will return false. So I use -30000 to express the meaning, but it is still imperfect. it is requiring a number to denoting impossible number or infinity simply
duplicate_array.resize(n,0);
for(int i=0; i<n; i++)
{
position.push_back(make_pair(i,-1));
}
}
void move(int j)
{
position[cur_i].second=j;
array[cur_i]=j;
if(duplicate_array[j]==0)
duplicate_array[j]=1;
else
duplicate_array[j]=2;
}
void un_move(int j)
{
position[cur_i].second=-1;
array[cur_i]=-30000;
if(duplicate_array[j]==1)
duplicate_array[j]=0;
else
duplicate_array[j]=1;
}
bool check()
{
vector<int>::iterator i = std::find(duplicate_array.begin(),duplicate_array.end(),2);
if(i != duplicate_array.end())
return false;
if(check_permutation(array) == false)
return false;
return true;
}
void write()
{
number_solution++;
for_each(position.begin(), position.end(), output_functor<pair<int,int> >());
cout<<endl;
}
private:
bool check_permutation(const vector<int>& p)
{
for(int i=0; i<n; i++)
{
for(int j=i+1,d=1; j<n; j++,d++)
{
if(p[i]+d == p[j] || p[i]-d == p[j])
return false;
}
}
return true;
}
};
void BackTracking(chess_board& c)
{
if(c.check() == false)
{
c.cur_i -= 1;
return;
}
else
{
if(c.cur_i == c.n)// this equality comparison is some tricky, note that following a move(), and assuming a solution has been generated, then cur_i will increase by 1.so in the recurrence of BackTracking cur_i will exceed the meaning of a position so that it will compare with n rather than n-1
{
c.write();
c.cur_i-=1; //this sentence is cope with the situation in which BackTracking terminated after a solution has been found
return;
}
else
{
for(int j=0; j<c.n; j++)
{
c.move(j);
c.cur_i += 1;
BackTracking(c);
c.un_move(j);
}
c.cur_i -= 1; //this sentence is cope with the situation in which BackTracking terminated after for loop over
}
}
}
int main()
{
int n;
cout<<"input the number of queen: ";
cin>>n;
chess_board c(n);
clock_t t1 = clock();
BackTracking(c);
cout<<"The number of solutions is: "<<c.number_solution<<endl;
clock_t t2 = clock();
cout<<"Times took:"<<double(t2-t1)/CLOCKS_PER_SEC;
system("pause");
return 0;
}
Note that this is just a “pure” BackTracking algorithm and it has not considered the optimization. I will optimize it later.
For the part of check function, I have observed the characteristic of permutation that is confirmed with n queen problem. The rule is defined as follow:
If the number of position p in permutation is i, then the vaule of position q(denoted by j) can't be q-p+i or p-q+i.(q∈(p,n-1] );
REVIST: (0,0)(1,2)(2,4)(3,3)(4,1) is a illegal solution which can be viewed as 0,2,4,3,1simply. 4(i) in position 2(p), 3(q's vaule: j) in position 3(q) ------ q-p+i = 5(no violation); p-q+i = 3(violation). (starting from zero))
It requires a two nested for loop to attaining. In addition, if there exist a method to constructing a NFA to recognize the permutation, the n queen problem algorithm will have Θ(n) efficiency class. But it seems impossible to do that because the FA needs counting and no way to abstract states.
The codes:
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <functional>
#include <ctime>
using namespace std;
template<class T>
struct output_functor : public unary_function<T,void>
{
void operator()(const T& p)const
{
cout<<"("<<p.first<<","<<p.second<<")"<<" ";
}
};
class chess_board
{
vector<pair<int, int> > position;
vector<int> array;
vector<int> duplicate_array;
public:
int n;
int cur_i;
int number_solution;
chess_board(int dim):n(dim),cur_i(0),number_solution(0)
{
position.reserve(n);
array.resize(n,-30000);//if using -1 to denoting no chess, it will contradict with the diagonal test. i.e. move{0,0}.the content of array is {0,-1,-1,-1}.the diagonal test will return false. So I use -30000 to express the meaning, but it is still imperfect. it is requiring a number to denoting impossible number or infinity simply
duplicate_array.resize(n,0);
for(int i=0; i<n; i++)
{
position.push_back(make_pair(i,-1));
}
}
void move(int j)
{
position[cur_i].second=j;
array[cur_i]=j;
if(duplicate_array[j]==0)
duplicate_array[j]=1;
else
duplicate_array[j]=2;
}
void un_move(int j)
{
position[cur_i].second=-1;
array[cur_i]=-30000;
if(duplicate_array[j]==1)
duplicate_array[j]=0;
else
duplicate_array[j]=1;
}
bool check()
{
vector<int>::iterator i = std::find(duplicate_array.begin(),duplicate_array.end(),2);
if(i != duplicate_array.end())
return false;
if(check_permutation(array) == false)
return false;
return true;
}
void write()
{
number_solution++;
for_each(position.begin(), position.end(), output_functor<pair<int,int> >());
cout<<endl;
}
private:
bool check_permutation(const vector<int>& p)
{
for(int i=0; i<n; i++)
{
for(int j=i+1,d=1; j<n; j++,d++)
{
if(p[i]+d == p[j] || p[i]-d == p[j])
return false;
}
}
return true;
}
};
void BackTracking(chess_board& c)
{
if(c.check() == false)
{
c.cur_i -= 1;
return;
}
else
{
if(c.cur_i == c.n)// this equality comparison is some tricky, note that following a move(), and assuming a solution has been generated, then cur_i will increase by 1.so in the recurrence of BackTracking cur_i will exceed the meaning of a position so that it will compare with n rather than n-1
{
c.write();
c.cur_i-=1; //this sentence is cope with the situation in which BackTracking terminated after a solution has been found
return;
}
else
{
for(int j=0; j<c.n; j++)
{
c.move(j);
c.cur_i += 1;
BackTracking(c);
c.un_move(j);
}
c.cur_i -= 1; //this sentence is cope with the situation in which BackTracking terminated after for loop over
}
}
}
int main()
{
int n;
cout<<"input the number of queen: ";
cin>>n;
chess_board c(n);
clock_t t1 = clock();
BackTracking(c);
cout<<"The number of solutions is: "<<c.number_solution<<endl;
clock_t t2 = clock();
cout<<"Times took:"<<double(t2-t1)/CLOCKS_PER_SEC;
system("pause");
return 0;
}
Note that this is just a “pure” BackTracking algorithm and it has not considered the optimization. I will optimize it later.
相关文章推荐
- Optimization of BackTracking algorithm for n queen problem
- rules for tracking down the cause of a problem
- General Approach for backtracking problem
- Can you give a visual explanation for the back propagation algorithm for neural networks?
- Linear-time algorithm for the maximum-subarray problem Java implementation
- The backtracking algorithm
- The backtracking algorithm
- 算法:Solutions for the Maximum Subsequence Sum Problem
- Sharepoint:The security validation for this page is invalid. Click Back in your Web browserSharepoin
- for the problem ImportError: cannot import name symbol_database 'text_format'
- Neural networks and the backpropagation algorithm
- This poses a huge problem for the Obama Administration
- git 本地分支和远程分支联系 Threre is no tracking information for the current branch
- Solve the printer problem for H5-01、H3-00
- The Case For Automating Manual Time Tracking
- Typically this problem occurs when you are putting in a data that is too long for the column. In t
- WMS has encountered a problem and needs to close. We are sorry for the inconvenience.
- UESTC_王之迷宫 2015 UESTC Training for Search Algorithm & String<Problem A>
- UESTC_Palindromic String 2015 UESTC Training for Search Algorithm & String<Problem M>
- the DataFormatString not work for the GridView BoundField problem