最优装载问题
问题描述:
有两个货轮,装载量分别为15吨与20吨,分别有10个集装箱,重量分别为4,7,3,3,4,5,3,4,1,1。现在要求用这两个货轮装下所有的集装箱,不计体积。
问题分析:
对于这个问题我们只需要考虑尽可能的去装满货轮1,剩余的集装箱全部放到C2中即可,也就是说我们相当于求解的是C1的最优装载,即C1最多能装多少。这个问题便转变成了一个特殊的0-1背包问题,特殊在重量与价值相等,显然我们可以使用动态规划算法求解,但是这里我们选择回溯法。
公式:
代码:
/*
问题描述:
有两个货轮,装载量分别为15吨与20吨。
分别有10个集装箱,重量分别为4,7,3,3,4,5,3,4,1,1。
现在要求用这两个货轮装下所有的集装箱,不计体积。
*/
#include <iostream>
#include <vector>
using namespace std;
int C1, C2;
int n;
int bestC;
int countAll;
vector<int> containers;
vector<int> isChoosed;
//结果打印函数
void print() {
cout << "C1的最优装载重量是:" << bestC<<" 吨"<<endl;
cout << "C1选择的物品重量分别为:" << endl;
for (int i = 0; i < n; i++) {
if (isChoosed[i] == 1) {
cout << "第 " << i << " 个集装箱重量 " << containers[i] << " 吨" << endl;
}
}
}
//装载重量计算函数
int weightCount(int t) {
int weight = 0;
for (int i = 0; i <= t; i++) {
if (isChoosed[i] == 1) {
weight += containers[i];
}
}
return weight;
}
//计算剩余重量的计算函数
int weightLeft(int t) {
int weight = 0;
for (int i = t + 1; i < n; i++) {
weight += containers[i];
}
return weight;
}
//判断最后需要装载到货轮2的集装箱是否重量在规定范围内
bool weightC2() {
int weightC1 = weightCount(n - 1);
int weightC2 = countAll - weightC1;
if (weightC2 > C2) {
return false;
}
}
//约束函数
bool bound(int t) {
//计算出当前货轮1中已经装载的货物的重量
int weight = weightCount(t);
//如果求得的重量已经超过了货轮1的承重,那么返回false
if (weight > C1) {
return false;
}
return true;
}
//剪枝函数
bool cut(int t) {
//如果发现当前方案下,已经装入的集装箱与剩余集装箱重量之和小于bestC
//那么就直接放弃该方案,实行剪枝,返回false
int weight = weightCount(t) + weightLeft(t);
if (weight < bestC || weight == bestC && t == n - 1) {
return false;
}
return true;
}
//回溯遍历函数
void backTrack(int t) {
if (t >= n) {
//记录当前最优装载方案
if (weightC2()) {
bestC = weightCount(n - 1);
print();
}
return;
}
else {
for (int i = 0; i <= 1; i++) {
isChoosed[t] = i;
if (bound(t) && cut(t)) backTrack(t + 1);
}
}
}
int main() {
bestC = 0;
countAll = 0;
//输入C1,C2的值
cout << "输入C1,C2的值" << endl;
cin >> C1;
cin >> C2;
//输入集装箱的总个数
cout << "输入集装箱的总个数" << endl;
cin >> n;
//输入各个集装箱的重量
for (int i = 0; i < n; i++) {
int container;
cout << "输入集装箱的重量" << endl;
cin >> container;
countAll += container;
containers.push_back(container);
isChoosed.push_back(0);
}
//输入完成之后开始回溯
backTrack(0);
}
运行结果如下:
C1的最优装载重量是:15 吨
C1选择的物品重量分别为:
第 4 个集装箱重量 4 吨
第 5 个集装箱重量 5 吨
第 7 个集装箱重量 4 吨
第 8 个集装箱重量 1 吨
第 9 个集装箱重量 1 吨
批处理作业调度问题
问题描述:
有n个待处理的作业,每个作业都需要在处理机A上处理完后再被处理机B处理,在处理机AB上的处理时间分别为a[i],b[i],在A、B上的结束时间分别为A[i]、B[i],现在要求最小,求最优处理方案耗时。
问题分析:
要解决这个问题,我们首先要列出公式,首先是A[i]和A[j-1]的关系,然后是B[j]和A[j]还有B[j-1]的关系。
公式:
得到的公式如下:
代码:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n;//批处理作业的个数
int bestTime = 0;//最短时间
vector<int> x;//处理顺序数组
vector<int> a;//作业在A上处理所需时长数组
vector<int> A;//作业在A上被处理完时的时间数组
vector<int> b;//作业在B上处理所需时长数组
vector<int> B;//作业在B上被处理完成的时间数组
int countTime(int t) {
int count = 0;
for (int i = 0; i <= t; i++) {
count += B[i];
}
return count;
}
void print() {
cout << "最短的时间是:" << bestTime << endl;
}
bool bound(int t) {
return true;
}
bool cut(int t) {
if (bestTime == 0) {
return true;
}
int nowTime = countTime(t);
if (bestTime < nowTime || bestTime == nowTime && t < n - 1) {
return false;
}
return true;
}
void backTrack(int t) {
if (t >= n) {
bestTime = countTime(n - 1);
print();
return;
}
else {
for (int i = t; i < n; i++) {
swap(x[t], x[i]);
if (t) {
A[t] = A[t - 1] + a[x[t]];
B[t] = max(A[t], B[t - 1]) + b[x[t]];
}
else {
A[t] = a[x[t]];
B[t] = A[t] + b[x[t]];
}
if(bound(t)&&cut(t)) backTrack(t + 1);
swap(x[t], x[i]);
}
}
}
int main() {
cout << "请输入n的值:" << endl;
cin >> n;
/*x = vector<int>(n);
a = vector<int>(n);
b = vector<int>(n);
A = vector<int>(n);
B = vector<int>(n);*/
for (int i = 0; i < n; i++) {
int c;
cout << "请输入作业 " << i << " 在A处理机上的运行时长";
cin >> c;
a.push_back(c);
cout << "请输入作业 " << i << " 在B处理机上的运行时长";
cin >> c;
b.push_back(c);
x.push_back(i);
A.push_back(0);
B.push_back(0);
}
backTrack(0);
}
运行结果如下:
请输入n的值:
3
请输入作业 0 在A处理机上的运行时长2
请输入作业 0 在B处理机上的运行时长1
请输入作业 1 在A处理机上的运行时长3
请输入作业 1 在B处理机上的运行时长1
请输入作业 2 在A处理机上的运行时长2
请输入作业 2 在B处理机上的运行时长3
最短的时间是:19
最短的时间是:18
n皇后问题:
问题描述:
n×n的棋盘,n个皇后,求n个皇后的放置方案个数。要求任意两个皇后都不在同一行、同一列或同一斜线上。
问题分析:
过于简单。。。不赘述,直接上代码。
代码:
#include <iostream>
#include <vector>
#include <cstdlib>
using namespace std;
int n;//这个问题是n皇后问题
int resultCount = 0;
vector<int> x;
bool cut(int t) {
for (int i = 0; i < t; i++) {
if (abs(x[i] - x[t]) == abs(i - t)) {
return false;
}
}
return true;
}
void backTrack(int t) {
if (t >= n) {
resultCount++;
return;
}
else {
for (int i = t; i < n; i++) {
swap(x[t], x[i]);
if(cut(t)) backTrack(t + 1);
swap(x[t], x[i]);
}
}
}
int main() {
cout << "请输入n的值:" << endl;
cin >> n;
//初始化数组x
for (int i = 0; i < n; i++) {
x.push_back(i);
}
backTrack(0);
cout << n << " 皇后问题解的个数为:" << resultCount << endl;
}
运行结果如下:
请输入n的值:
8
8 皇后问题解的个数为:92
m着色图问题
问题描述 :
问题分析:
本题中,我们要求的是图的m着色问题,即给出的无向连通图是多少着色图,我们采用n * n维向量vector来表示邻接矩阵,遍历邻接矩阵之后我们可以判断各个节点之间是否相邻,相邻节点的着色不能相同,否则结束当前策略,回溯到上一步。
对于m的值,我们是不确定的,所以我们从1开始累加测试m的值。
代码:
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
int m = 1;//假定为m着色图
int n;//点的个数
bool success = false;
vector<int> ei;
vector<vector<int>> e;//邻接矩阵
vector<int> point;
void print() {
cout << "着色成功!" << endl;
cout << "该图是:" << m - 1 << "色图";
}
bool cut(int t) {
//遍历矩阵
for (int i = 0; i <= t; i++) {
for (int j = 0; j <= t; j++) {
if (e[i][j] == 1 && point[i] == point[j] && i != j) {
return false;
}
}
}
return true;
}
void backTrack(int t) {
if (success) {
return;
}
if (t >= n) {
//输出结果
print();
//着色成功
success = true;
return;
}
else {
for (int i = t; i < m; i++) {
point[t] = i;
if(cut(t)) backTrack(t + 1);
}
}
}
int main() {
//输入节点个数
cout << "请输入节点的个数" << endl;
cin >> n;
//初始化邻接矩阵
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
ei.push_back(0);
}
e.push_back(ei);
ei.clear();
}
//初始化节点数组
for (int i = 0; i < n; i++) {
point.push_back(0);
}
int countE;
cout << "请输入边的条数:" << endl;
cin >> countE;
for (int i = 0; i < countE; i++) {
cout << "请输入第:" << i << "条边的两个顶点:" << endl;
int pointA;
int pointB;
cin >> pointA;
cin >> pointB;
//在邻接矩阵中将对应边标记为1
e[pointA][pointB] = 1;
e[pointB][pointA] = 1;
}
while (!success) {
backTrack(0);
m++;
}
}
输入:
请输入节点的个数
5
请输入边的条数:
8
请输入第:0条边的两个顶点:
0 1 0 2 0 3 1 2 1 3 1 4 2 3 3 4
输出:
着色成功!
该图是:4色图
至此,常见的例题已经解决完毕,感谢观看~~