網站首頁 編程語言 正文
算法思想
分支限界法與回溯法的求解目標不同。
回溯法的求解目標是找出解空間中滿足約束條件的所有解,而分支限界法的求解目標則是找出滿足約束條件的一個解,或是在滿足約束條件的解中找出使某一目標函數值達到極大或極小的解,即在某種意義下的最優解。
由于求解目標不同,導致分支限界法與回溯法對解空間的搜索方式也不相同。
回溯法以深度優先的方式搜索解空間,而分支限界法則以廣度優先或以最小耗費優先的方式搜索解空間。
回溯法對解空間做深度優先搜索時,有遞歸回溯和迭代回溯(非遞歸)兩種方法,但一般情況下用遞歸方法實現回溯法。
常見的兩種分支限界法
先進先出(FIFO)隊列式:在先進先出的分支限界法中,用隊列作為組織活結點表的數據結構,并按照隊列先進先出的原則選擇結點作為擴展結點。
? ?優先隊列(PQ):用優先隊列作為組織活結點表的數據結構。
回溯代碼
#include<stdio.h>
int n,c,bestp;//物品的個數,背包的容量,最大價值
int p[10000],w[10000],x[10000],bestx[10000];//物品的價值,物品的重量,x[i]暫存物品的選中情況,物品的選中情況
void Backtrack(int i,int cp,int cw)
{ //cw當前包內物品重量,cp當前包內物品價值
int j;
if(i>n)//回溯結束
{
if(cp>bestp)
{
bestp=cp;
for(i=0;i<=n;i++) bestx[i]=x[i];
}
}
else
for(j=0;j<=1;j++)
{
x[i]=j;
if(cw+x[i]*w[i]<=c)
{
cw+=w[i]*x[i];
cp+=p[i]*x[i];
Backtrack(i+1,cp,cw);
cw-=w[i]*x[i];
cp-=p[i]*x[i];
}
}
}
int main()
{
int i;
bestp=0;
printf("請輸入背包最大容量:\n");
scanf("%d",&c);
printf("請輸入物品個數:\n");
scanf("%d",&n);
printf("請依次輸入物品的重量:\n");
for(i=1;i<=n;i++)
scanf("%d",&w[i]);
printf("請依次輸入物品的價值:\n");
for(i=1;i<=n;i++)
scanf("%d",&p[i]);
Backtrack(1,0,0);
printf("最大價值為:\n");
printf("%d\n",bestp);
printf("被選中的物品依次是(0表示未選中,1表示選中)\n");
for(i=1;i<=n;i++)
printf("%d ",bestx[i]);
printf("\n");
return 0;
}
回溯結果
分支限界代碼
#include<iostream>
#include<queue>
using namespace std;
const int maxn=99;
int n,c;
int w[maxn];
int v[maxn];
int bestv=0;
int bestx[maxn];
int total=1; //解空間中的節點數累計,全局變量
struct nodetype //隊列中的結點類型
{
int no; //結點編號,從1開始
int i; //當前結點在搜索空間中的層次
int w; //當前結點的總重量
int v; //當前結點的總價值
int x[maxn]; //當前結點包含的解向量
double ub; //上界
};
void input()
{
cout<<"請輸入物品的個數:"<<endl;
cin>>n;
cout<<"請輸入每個物品的重量及價值(如5 4):"<<endl;
for(int i = 1; i <= n; i++)
{
cin>>w[i]>>v[i];
}
cout<<"請輸入背包的容量:"<<endl;
cin>>c;
}
void bound(nodetype &e) //計算分支結點e的上界
{
int i=e.i+1; //考慮結點e的余下物品
int sumw=e.w;
double sumv=e.v;
while((sumw+w[i]<=c)&&i<=n)
{
sumw+=w[i];
sumv+=v[i];
i++;
}
if(i<=n) //余下物品只能部分裝入
e.ub=sumv+(c-sumw)*v[i]/w[i];
else e.ub=sumv;
}
void enqueue(nodetype e,queue<nodetype> &qu)
//結點e進隊qu
{
if(e.i==n) //到達葉子節點,不在擴展對應一個解
{
if(e.v>bestv) //找到更大價值的解
{
bestv=e.v;
for(int j=1;j<=n;j++)
bestx[j]=e.x[j];
}
}
else qu.push(e); //非葉子結點進隊
}
void bfs()
{
int j;
nodetype e,e1,e2;
queue<nodetype> qu;
e.i=0;
e.w=0;
e.v=0;
e.no=total++;
for(j=1;j<=n;j++)
e.x[j]=0;
bound(e);
qu.push(e);
while(!qu.empty())
{
e=qu.front();qu.pop(); //出隊結點e
if(e.w+w[e.i+1]<=c) //剪枝,檢查左孩子結點
{
e1.no=total++; //建立左孩子結點
e1.i=e.i+1;
e1.w=e.w+w[e1.i];
e1.v=e.v+v[e1.i];
for(j=1;j<=n;j++)
e1.x[j]=e.x[j];
e1.x[e1.i]=1;
bound(e1); //求左孩子的上界
enqueue(e1,qu); //左孩子結點進隊
}
e2.no=total++;
e2.i=e.i+1;
e2.w=e.w;
e2.v=e.v;
for(j=1;j<=n;j++)
e2.x[j]=e.x[j];
e2.x[e2.i]=0;
bound(e2);
if(e2.ub>bestv) //若右孩子結點可行,則進隊,否則被剪枝
enqueue(e2,qu);
}
}
void output()
{
cout<<"最優值是:"<<bestv<<endl;
cout<<"(";
for(int i=1;i<=n;i++)
cout<<bestx[i]<<" ";
cout<<")";
}
int main()
{
input();
bfs();
output();
return 0;
}
分支限界結果
原文鏈接:https://blog.csdn.net/weixin_55764157/article/details/124675936
相關推薦
- 2024-03-10 【Redis】Redis中大key怎么處理?
- 2022-04-22 nvm切換node版本后提示npm : 無法將“npm”項識別為 cmdlet、函數、腳本文件或可運
- 2024-03-28 存儲過程整合springboot
- 2023-11-20 如何設置樹莓派4B的頻率?
- 2021-12-15 Redis可視化工具Redis?Desktop?Manager的具體使用_Redis
- 2022-07-22 如何快速刪除node_modules目錄方法詳解
- 2022-06-30 python神經網絡MobileNet模型的復現詳解_python
- 2022-03-28 Python實現網頁文件轉PDF文件和PNG圖片的示例代碼_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支