N皇后问题
算法描述:
利用回溯法求解n皇后问题,函数Place起到约束函数的作用,判断两个皇后是否在同一行或在同一斜线上。问题中还有一个约束条件就是所求的解不对称,这里加一个判断条件。找到可行解就打印出来,不然继续深度搜索。
源程序:
#include<iostream>
#include<math.h>
using namespace std;
bool Place(int k,int i,int* x)
{
//判断前k个皇后和第k+1个皇后是否//在同一列或同一斜线上
int j;
for(j=0;j<k;j++)
{
if((x[j]==i)||(abs(x[j]-i)==abs(j-k)))
return false;
}
return true;
}
void NQueens(int k,int n,int* x)
{
int i;
for(i=0;i<n;i++)//显示约束的第一种观点,x[k]=0...n-1;
{
if(Place(k,i,x))//约束函数
{
if(k!=0||(k==0&&i<n/2))//求其中不对称的解
{
x[k]=i;
if(k==n-1)
{
for(i=0;i<n-1;i++)
{
cout<<x[i]<<" ";//输出可行解
}
cout<<x[i];
cout<<endl;
}
else
{
NQueens(k+1,n,x);//深度优先进入下一层
}
}
}
}
}
int main()
{
int n,x[100];
cin>>n;
NQueens(0,n,x);
return 0;
}
子集和数的问题
算法描述:
用回溯法求解自己和数的问题,如果初始所有数相加大于M,进行回溯法求解。先将w按非递减次序排列。每次加入一个数,如果剩下的所有数加入都仍然小于M,不满足条件,加入的数和前面已经加入的数要小于等于M,不然不是解。最后判断如果满足条件输出可行解。
源程序:
#include<iostream>
using namespace std;
int flag=0;//解的个数
void SumofSub(int s,int k,int r,int w[],int x[],int n,int m,int y[])
{
int i,j,z;
for(i=1;i>=0;i--)
{
x[k]=i;
s+=x[k]*w[k];
r-=w[k];
if(s==m){
flag++;
for(j=0;j<n-1;j++)
for(z=0;z<n;z++)
{
if(y[z]==j)
cout<<x[z]<<" ";
}
for(z=0;z<n;z++)
{
if(y[z]==j)
cout<<x[z]<<endl;
}
}
else
if(s+r>=m&&s+w[k+1]<=m)
{
SumofSub(s,k+1,r,w,x,n,m,y);//搜索下一层
}
s-=x[k]*w[k];
r+=w[k];
}
}
int main()
{
int n,m,i,j,s=0,r=0;
int w[100],x[100],y[100];
cin>>n>>m;
for(i=0;i<n;i++)
{
cin>>w[i];
y[i]=i;
x[i]=0;
r+=w[i];
}
//从小到大排序
for(i=0;i<n-1;i++)
{
for(j=0;j<n-i-1;j++)
{
if(w[j]>w[j+1])
{
swap(w[j],w[j+1]);
swap(y[j],y[j+1]);
}
}
}
//保证初始条件成立
if(s+r>=m)SumofSub(s,0,r,w,x,n,m,y);
//没有答案情况
if(flag==0)
cout<<"no solution!"<<endl;
return 0;
}
回溯法0/1背包问题
算法描述:
利用回溯法解决0/1背包问题,这个问题是一个最优化问题,使用约束函数剪去的是不含可行解的子树,使用限界函数可以进一步剪去那些不含最优解的分支。
Knapsack是实现0/1背包回溯算法,Bound是上界函数。在算法执行时,一旦遇到一个答案结点,变计算该结点的收益值fp。比较与现在的fp值,取收益最大的。
源程序:
#include <iostream>
using namespace std;
int w[100];//价值
int p[100];//收益
int n,m;
int Bound(int k,int cp,int cw){
//cp是当前收益,cw是当前背包重量,k是当前待考察的物品编号
int b=cp,c=cw;
int i;
for(i=k+1;i<n;i++){
c+=w[i];
if(c<m)
b+=p[i];
else
return (b+(1-(c-m)/w[i])*p[i]);
}
return b;
}
void BKnapsack(int k,int cp,int cw,int &fp,int *x,int *y){
//fp是当前最大收益
int j;
int bp;
//考察左孩子结点
if(cw+w[k]<=m){
y[k]=1;
if(k<n-1)
BKnapsack(k+1,cp+p[k],cw+w[k],fp,x,y);
if(cp+p[k]>fp&&k==n-1){
fp=cp+p[k];
for(j=0;j<=k;j++)
x[j]=y[j];
}
}
//考察右孩子结点
if(Bound(k,cp,cw)>=fp){
y[k]=0;
if(k<n-1)
BKnapsack(k+1,cp,cw,fp,x,y);
if(cp>fp&&k==n-1){
fp=cp;
for(j=0;j<=k;j++)
x[j]=y[j];
}
}
}
int BKnapsack(int *x){
//一维数组x中返回最优解,函数返回最优解值
int fp;
int y[100]={0};
BKnapsack(0,0,0,fp,x,y);
return fp;
}
int main(){
cin>>n>>m;
int x[100];
int i,xx;
for(i=0;i<n;i++)
cin>>w[i];
for(i=0;i<n;i++)
cin>>p[i];
xx=BKnapsack(x);
cout<<xx<<endl;
return 0;
}