本系列所有代码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人。给定2 个n×n矩阵P和Q。P[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;
}