日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法设计与分析——分支限界法——装载问题

發布時間:2023/12/4 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法设计与分析——分支限界法——装载问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

有一批共個集裝箱要裝上2艘載重量分別為C1和C2的輪船,其中集裝箱i的重量為Wi,且裝載問題要求確定是否有一個合理的裝載方案可將這個集裝箱裝上這2艘輪船。如果有,找出一種裝載方案。

容易證明:如果一個給定裝載問題有解,則采用下面的策略可得到最優裝載方案。
(1)首先將第一艘輪船盡可能裝滿;
(2)將剩余的集裝箱裝上第二艘輪船。
思想
在算法的循環體中,首先檢測當前擴展結點的左兒子結點是否為可行結點。如果是則將其加入到活結點隊列中。然后將其右兒子結點加入到活結點隊列中(右兒子結點一定是可行結點)。2個兒子結點都產生后,當前擴展結點被舍棄。

活結點隊列中的隊首元素被取出作為當前擴展結點,由于隊列中每一層結點之后都有一個尾部標記-1,故在取隊首元素時,活結點隊列一定不空。當取出的元素是-1時,再判斷當前隊列是否為空。如果隊列非空,則將尾部標記-1加入活結點隊列,算法開始處理下一層的活結點。

節點的左子樹表示將此集裝箱裝上船,右子樹表示不將此集裝箱裝上船。設bestw是當前最優解;ew是當前擴展結點所相應的重量;r是剩余集裝箱的重量。則當ew+r<bestw時,可將其右子樹剪去,因為此時若要船裝最多集裝箱,就應該把此箱裝上船。另外,為了確保右子樹成功剪枝,應該在算法每一次進入左子樹的時候更新bestw的值。

為了在算法結束后能方便地構造出與最優值相應的最優解,算法必須存儲相應子集樹中從活結點到根結點的路徑。為此目的,可在每個結點處設置指向其父結點的指針,并設置左、右兒子標志。

找到最優值后,可以根據parent回溯到根節點,找到最優解。

優先隊列寫法:

#include<iostream> #include<queue>//優先隊列的頭文件 using namespace std; //子集樹中節點的定義 class bbnode{ public:bbnode *parent;//指向父節點的指針 bool Lchild;//是否是左孩子結點的標記 }; //優先隊列中節點的定義 class HeapNode{public:bbnode *ptr; //指向活結點在子集樹中相應節點的指針int uweight; //活結點的優先級(上界) //優先級的定義:從根節點到節點x的路徑相應的載重量加上剩余集裝箱的重量之和int level; //活結點在子集樹中所處的層次 }; struct compare{bool const operator()(HeapNode *&a,HeapNode *&b){return (a->uweight) < (b->uweight);//最大堆 } }; //該函數是將新產生的活結點加入到子集樹中,并將這個節點插入到表示活結點優先隊列的最大堆中 void AddLiveNode(priority_queue<HeapNode*,vector<HeapNode*>,compare> &Q,bbnode *parent,bool isLeft,int uWeight,int level) {//先在子集樹中建立這個節點bbnode *b = new bbnode;b->parent = parent;b->Lchild = isLeft;//再在優先隊列中新建一個節點HeapNode *h = new HeapNode;h->ptr = b;//將剛在添加到子集樹中的新節點b再賦值給將要添加到優先隊列中的節點h h->uweight = uWeight;h->level = level; //將新建的節點添加到優先隊列Q.push(h); }int MaxLoading(int *weight,int n,int *bestx,int c) {priority_queue<HeapNode*,vector<HeapNode*>,compare> Heap;int i=0;// 表示當前所在子集樹的層次int now_weight=0;//表示當前已裝載的重量int node_priority=0; //優先級————裝載的最大上界=當前裝載量+剩余集裝箱的重量HeapNode *H;//用于保存從優先隊列出來的節點 bbnode *B;//子集樹上的擴展節點int *remains; //剩余集裝箱 , 記載未裝的貨物remains = new int[n];remains[n-1]=0;//當到達最后的葉子節點時,沒有剩余的貨物 for(int j=n-2;j>=0;j--){ //計算當到達指定層時的剩余數組 remains[j]=remains[j+1]+weight[j+1];}while(i!=n)//沒有到達葉子節點時 ,到達第i層 {if(now_weight+weight[i]<=c)//即當前的重量能夠裝的下 =進入左子樹 左孩子 {node_priority=(now_weight+weight[i]) +remains[i];//優先級 =當前裝載量+剩余集裝箱的重量AddLiveNode(Heap,B,true,node_priority,i+1);}// 進入右子樹 右孩子 node_priority=(now_weight) +remains[i];//優先級 =當前裝載量+剩余集裝箱的重量AddLiveNode(Heap,B,false,node_priority,i+1);H = Heap.top(); //查詢優先隊列隊頭結點 Heap.pop(); //隊頭結點出隊 i=H->level;B=H->ptr; //記錄當前到達的結點 now_weight=H->uweight - remains[i-1]; //計算當前已經裝載量 }// 記錄已裝載貨物 for(int j=n-1;j>=0;j--){bestx[j]=B->Lchild? 1:0;B=B->parent;}return now_weight; //返回最優裝載量 } int main() {int n; //貨物數 int shipNum; //貨船數量 int bestw; //最優裝載量 int weight[n]; //貨物總重量 int bestx[n]; //最優的裝載序列 int c1=0; //第一艘船的裝載重量 int c2=0; //第二艘船的裝載重量 cout<<"請輸入貨物數:";cin>>n;cout<<"請輸入貨船的數量:";cin>>shipNum;cout<<"請輸入貨物的重量序列:";for(int i=0;i<n;i++){cin>>weight[i];}cout<<"請輸入兩艘船的載重量:";cin>>c1>>c2;int maxc=0;//船的最大裝載重量 int sumc=c1+c2;//船的裝載重和 if(c1>c2)maxc=c1;else maxc=c2;int maxweight=0;//貨物中的最大重量int sumweight=0; //貨船總重量 for(int i=0;i<n;i++){if(weight[i]>maxweight){maxweight=weight[i];}sumweight+=weight[i];}if(maxweight>maxc){printf("貨物重量超過貨船的載重量,無法裝載!");return 0;} if(sumweight>sumc){printf("貨物總重量超過貨船的總載重量,無法裝載!");return 0;}MaxLoading(weight,n,bestx,c1);cout<<"裝載序列為:"; for(int i=0;i<n;i++){cout<<bestx[i]<<" ";}cout<<endl;cout<<"第1艘船的最優裝載量為:"<<MaxLoading(weight,n,bestx,c1)<<endl;cout<<"裝載的貨物為:";for(int i=0;i<n;i++){if(bestx[i]!=0)cout<<weight[i]<<" ";}cout<<endl;cout<<"第2艘船的最優裝載量為:"<<sumweight-MaxLoading(weight,n,bestx,c1)<<endl;cout<<"裝載的貨物為:";for(int i=0;i<n;i++){if(bestx[i]!=1)cout<<weight[i]<<" ";}}


堆寫法:

#include<iostream> #include<queue>//優先隊列的頭文件 using namespace std;class bbnode{ public:bbnode *parent;//指向父節點的指針 bool Lchild;//是否是左孩子結點的標記 }; //優先隊列中節點的定義 class HeapNode{public:operator double() const{return uweight;}int operator <= (HeapNode hn) const{return uweight<=hn.uweight; }int operator < (HeapNode hn) const{return uweight<hn.uweight; }int operator >= (HeapNode hn) const{return uweight>=hn.uweight; }int operator > (HeapNode hn) const{return uweight>hn.uweight; }int operator == (HeapNode hn) const{return uweight==hn.uweight; }HeapNode(){}bbnode *ptr; //指向活結點在子集樹中相應節點的指針int uweight; //活結點的優先級(上界) //優先級的定義:從根節點到節點x的路徑相應的載重量加上剩余集裝箱的重量之和int level; //活結點在子集樹中所處的層次 }; class MaxHeap { public:MaxHeap(int n); //構造函數,N表示堆中能存儲的最大元素的個數 void Insert(HeapNode heapNode); //向堆中插入一個結點 void DeleteMax(HeapNode &heapNode); //刪除堆中的最大結點 private:int size; HeapNode *MH; void Delete(HeapNode &heapNode,int index); //刪除堆中標號為index的元素,index從1開始,即1表示最大元素 void SiftUp(int index); //將堆中標號為index的元素,向上調整,保證堆結構 void SiftDown(int index); //將堆中標號為index的元素,向下調整,保證堆結構 };MaxHeap::MaxHeap(int n) {size=0;MH=new HeapNode[n]; }void MaxHeap::SiftUp(int index) {if(index<=1)return;bool done=false;do{if(MH[index]>MH[index/2]){HeapNode tmp=MH[index];MH[index]=MH[index/2];MH[index/2]=tmp;}elsedone=true;index=index/2;}while(index>1&&!done); }void MaxHeap::SiftDown(int index) {if(2*index>size)return;bool done=false;do{index=2*index;if(index+1<=size&&MH[index+1]>MH[index])index=index+1;if(MH[index/2]<MH[index]){HeapNode tmp=MH[index];MH[index]=MH[index/2];MH[index/2]=tmp;}elsedone=true;}while(2*index<=size&&!done); }void MaxHeap::Insert(HeapNode heapNode) {size+=1;MH[size]=heapNode;SiftUp(size); }void MaxHeap::Delete(HeapNode &heapNode,int index) {if(index<1||index>size){return;}HeapNode x=MH[index],y=MH[size];heapNode=MH[index];size-=1;if(index==size+1)return;MH[index]=y;//將原來堆中的最后一個放到要被刪除的位置,再繼續調整堆 if(y>=x)SiftUp(index);elseSiftDown(index); }void MaxHeap::DeleteMax(HeapNode &heapNode) {Delete(heapNode,1); } //子集樹中節點的定義//該函數是將新產生的活結點加入到子集樹中,并將這個節點插入到表示活結點優先隊列的最大堆中 void AddLiveNode(MaxHeap &Q,bbnode *parent,bool isLeft,int uWeight,int level) {//先在子集樹中建立這個節點bbnode *b = new bbnode;b->parent = parent;b->Lchild = isLeft;//再在優先隊列中新建一個節點HeapNode H;H.ptr = b;//將剛在添加到子集樹中的新節點b再賦值給將要添加到優先隊列中的節點h H.uweight = uWeight;H.level = level; //將新建的節點添加到優先隊列Q.Insert(H); }int MaxLoading(int *weight,int n,int *bestx,int c) {MaxHeap *Maxhp=new MaxHeap(100);;int i=0;// 表示當前所在子集樹的層次int now_weight=0;//表示當前已裝載的重量int node_priority=0; //優先級————裝載的最大上界=當前裝載量+剩余集裝箱的重量HeapNode H;//用于保存從優先隊列出來的節點 bbnode *B;//子集樹上的擴展節點int *remains; //剩余集裝箱 , 記載未裝的貨物remains = new int[n];remains[n-1]=0;//當到達最后的葉子節點時,沒有剩余的貨物 for(int j=n-2;j>=0;j--){ //計算當到達指定層時的剩余數組 remains[j]=remains[j+1]+weight[j+1];}while(i!=n)//沒有到達葉子節點時 ,到達第i層 {if(now_weight+weight[i]<=c)//即當前的重量能夠裝的下 =進入左子樹 左孩子 {node_priority=(now_weight+weight[i]) +remains[i];//優先級 =當前裝載量+剩余集裝箱的重量AddLiveNode(*Maxhp,B,true,node_priority,i+1);}// 進入右子樹 右孩子 node_priority=(now_weight) +remains[i];//優先級 =當前裝載量+剩余集裝箱的重量AddLiveNode(*Maxhp,B,false,node_priority,i+1);Maxhp->DeleteMax(H); //查詢優先隊列隊頭結點 i=H.level;B=H.ptr; //記錄當前到達的結點 now_weight=H.uweight - remains[i-1]; //計算當前已經裝載量 }// 記錄已裝載貨物 for(int j=n-1;j>=0;j--){bestx[j]=B->Lchild? 1:0;B=B->parent;}return now_weight; //返回最優裝載量 } int main() {int n; //貨物數 int shipNum; //貨船數量 int bestw; //最優裝載量 int weight[n]; //貨物總重量 int bestx[n]; //最優的裝載序列 int c1=0; //第一艘船的裝載重量 int c2=0; //第二艘船的裝載重量 cout<<"請輸入貨物數:";cin>>n;cout<<"請輸入貨船的數量:";cin>>shipNum;cout<<"請輸入貨物的重量序列:";for(int i=0;i<n;i++){cin>>weight[i];}cout<<"請輸入兩艘船的載重量:";cin>>c1>>c2;int maxc=0;//船的最大裝載重量 int sumc=c1+c2;//船的裝載重和 if(c1>c2)maxc=c1;else maxc=c2;int maxweight=0;//貨物中的最大重量int sumweight=0; //貨船總重量 for(int i=0;i<n;i++){if(weight[i]>maxweight){maxweight=weight[i];}sumweight+=weight[i];}if(maxweight>maxc){printf("貨物重量超過貨船的載重量,無法裝載!");return 0;} if(sumweight>sumc){printf("貨物總重量超過貨船的總載重量,無法裝載!");return 0;}MaxLoading(weight,n,bestx,c1);cout<<"裝載序列為:"; for(int i=0;i<n;i++){cout<<bestx[i]<<" ";}cout<<endl;cout<<"第1艘船的最優裝載量為:"<<MaxLoading(weight,n,bestx,c1)<<endl;cout<<"裝載的貨物為:";for(int i=0;i<n;i++){if(bestx[i]!=0)cout<<weight[i]<<" ";}cout<<endl;cout<<"第2艘船的最優裝載量為:"<<sumweight-MaxLoading(weight,n,bestx,c1)<<endl;cout<<"裝載的貨物為:";for(int i=0;i<n;i++){if(bestx[i]!=1)cout<<weight[i]<<" ";}}

總結

以上是生活随笔為你收集整理的算法设计与分析——分支限界法——装载问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。