算法篇-12-分支限界-限定价格内最小重量机器设计&运动员最佳组队

来源:互联网 发布:不在淘宝 提过码 编辑:程序博客网 时间:2024/05/05 07:27

本系列所有代码https://github.com/YIWANFENG/Algorithm-github

限定价格内最小重量机器设计

题目:

一个机器,由n个部件组成,每个部件都可从m各不同的供应厂商处购得,设w[i][j]是从j处购得部件i的重量,c[i][j]是价格。给出总价格不超过d的最小重量机器设计。

 

算法分析与相关公式:

既然要最小重量,我们就选中以当前购物方案E的总重量w作为优先级。

其中当前E还应包含c(当前花费),以避免花费超界,既可以在此设置限界函数。当然还应有一个level保存当前方案已经选购到了第几个部件。在搜索中很明显,若当前优先队列头上的元素的level超过n,即可视为找到一最优解,应退出搜索。

在程序一开始先选购第一个,然后把所有选择他的方案求出,若方案超费,不入优先队列。

选完一节点后从优先队列中选取头部继如此过程即可。

#include <iostream>#include <queue>#include <vector> //限定价格内最小重量机器设计 - 分支限界 using namespace std;class Node{public:int *x;//结果 int w;int c;int level;bool operator<(const Node & a)  const{return w<a.w;}};class Machine{private:int n;//n个部件 int m;//m个供应商 int *weight;//weight[i][j]相应重量 int *cost;//cost[i][j]相应价格 int d;//总价格 public:int Solve(int n_,int m_,int *w_,int *c_,int d_,int *result){n = n_;  m = m_;weight = w_;cost = c_;d = d_;priority_queue<Node> q;Node E;E.c = 0;E.w = 0;E.level = -1;E.x = new int[n];while(E.level+1<n)  {for(int i=0;i<m;++i) {//确保不超价格 if(E.c+cost[(E.level+1)*m+i]<=d) {Node N;N.c = E.c+cost[(E.level+1)*m+i];N.w = E.w+weight[(E.level+1)*m+i];N.level = E.level+1;N.x = new int[n];for(int j=0;j<=E.level;++j) {N.x[j] = E.x[j];}N.x[E.level+1] = i;q.push(N);}}delete []E.x;if(q.empty()) break;E = q.top();q.pop();}if(E.x == NULL) return -1;for(int i=0;i<n;++i) {result[i] = E.x[i];}delete []E.x;while(!q.empty()) {E = q.top();delete [] E.x;q.pop();}return E.w;}};int main(){int n=3,m=3,d=4;int c[] = {1,2,3,3,2,1,2,2,2};int w[] = {1,2,3,3,2,1,2,2,2};int *result = new int[n];Machine ma;cout<<"BestW:"<<ma.Solve(n,m,w,c,d,result)<<endl;for(int i=0;i<n;++i) {cout<<result[i]<<' ';}delete [] result;cin.get();return 0;}


运动员最佳组队

题目:

 羽毛球队有男女运动员各n人。给定n×n矩阵PQP[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势;Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势。由于技术配合和心理状态等各种因素影响,P[i][j]不一定等于Q[j][i]。男运动员i和女运动员j配对组成混合双打的男女双方竞赛优势为P[i][j]*Q[j][i]。设计一个算法,计算男女运动员最佳配对法,使各组男女双方竞赛优势的总和达到最大。

 

算法分析与相关公式:

此题求解类似限定价格内最小重量机器设计,不同之处在于此题解空间为排列树。

在这里我们选择的是

int level; //level号男运动员

int c; //目前安排能力加成

int *x; //人员安排方式 

在每一次搜索扩展时,level之前的运动员已经安排好了,所以只需要安排level之后的即可。

在这我并没有添加限界函数。

#include <iostream>#include <queue>#include <vector> //  运动员最佳组队 - 分支限界 using namespace std;class Node {public:int level;//第level号男运动员int c;//目前安排能力加成int *x;//人员安排方式 bool operator <(const Node &a) const {return this->c < a.c; }}; void Swap(int &a,int &b){if(a==b) return;int c =a;a = b;b = c;}class Organize{private:int n;//n男n女 int *P;//p[i][j] 是男i与女j一起时的能力加成 int *Q;//Q[i][j] 是女i与男j一起时的能力加成int bestc;public:int Solve(int n_,int *p_,int *q_,int *result){n = n_;Q = q_;P = p_;Node E;E.c = 0;E.level = 0;E.x = new int[n];for(int i=0;i<n;++i) E.x[i] = i;priority_queue<Node> qq;bestc = 0;while(E.level<=n) {//产生当前节点的扩展节点 if(E.level == n) {if(E.c>bestc) {bestc = E.c;for(int i=0;i<n;++i) {result[i]=E.x[i];//if(E.c == 55)//cout<<result[i]<<endl;}delete [] E.x;}}else {for(int i=E.level;i<n;++i) {Swap(E.x[E.level],E.x[i]);Node N;N.c = E.c + P[E.level*n+E.x[E.level]] * Q[E.x[E.level]*n+E.level];N.level = E.level+1;N.x = new int[n];for(int j=0;j<n;++j) N.x[j] = E.x[j];qq.push(N);Swap(E.x[E.level],E.x[i]);}delete [] E.x;}if(qq.empty()) break;E= qq.top() ; qq.pop();}while(!qq.empty()) {E = qq.top();delete [] E.x;qq.pop();}return bestc;}};int main(){int n = 3;int p[] = {10,2,3,2,3,4,3,4,5};int q[] = {2,2,2,3,5,3,4,5,1};int *result = new int [n];Organize org;cout<<"Best:"<<org.Solve(n,p,q,result)<<endl;for(int i=0;i<n;++i) cout<<result[i]<<' ';cin.get();delete [] result;return 0;}




0 0
原创粉丝点击