回溯法例子

这篇博客探讨了回溯法在解决N皇后问题、子集和数问题以及0/1背包问题中的应用。通过算法描述和源程序,详细阐述了如何利用回溯法寻找这些经典问题的解,并强调了在不同问题中回溯法如何处理约束条件以找到有效解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值