赞
踩
分别用蛮力法、回溯法、分支限界法求解任务分配问题。
假设有n个任务需要分配给n个人执行,每个人只执行一个任务,每个任务只由一个人执行。第i个人执行第j个任务的成本是Cij(1<=i,j<=n), 求解初最小成本的分配方案。
最简单的算法是:蛮力法,这里采用增量穷举法求出所有的分配方案ps,再计算出每种方案的成本,比较求出最小成本的方案,即最优方案。
#include<iostream> #include<vector> using namespace std; #define INF 9999 //最大成本值 #define MAXN 21 int n; int c[MAXN][MAXN]; vector<vector<int>> ps; void Insert(vector<int> s, int i, vector<vector<int>> &ps1) { //在每个集合元素中插入i得到ps1 vector<int> s1; vector<int>::iterator it; for (int j = 0; j < i; j++) //在s的每个位置都插入i { s1 = s; it = s1.begin() + j; //求出插入位置 s1.insert(it, i); //插入整数i ps1.push_back(s1); //添加到ps1中 } } void Perm(int n) { vector<vector<int>> ps1; //临时存放子排列 vector<vector<int>>::iterator it; //全排列迭代器 vector<int> s, s1; s.push_back(1); ps.push_back(s); //添加{1}集合元素 for (int i = 2; i <= n; i++) //循环添加1~n { ps1.clear(); //ps1存放插入i的结果 for (it = ps.begin(); it != ps.end(); ++it) { Insert(*it, i, ps1); //在每个集合元素中间插入i得到ps1 } ps = ps1; } } void Allocate(int n, int& mini, int& minc) //求任务分配问题的最优方案 { Perm(n); for (int i = 0; i < ps.size(); i++) //求出每个方案的成本 { int cost = 0; for (int j = 0; j < ps[i].size(); j++) { cost += c[j][ps[i][j] - 1]; } if (cost < minc) { minc = cost; mini = i; } } } int main() { int mincost = INF, mini; cin >> n; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cin >> c[i][j]; Allocate(n, mini, mincost); printf("最优方案:\n"); for (int k = 0; k < ps[mini].size(); k++) { printf("第%d个人安排任务%d\n", k + 1, ps[mini][k]); } printf("总成本=%d\n", mincost); return 0; }
蛮力法求解任务分配问题的时间复杂度为:O( n x n!)
#include<iostream> #include<queue> #include<vector> using namespace std; #define INF 9999 #define MAXN 21 int n; int c[MAXN][MAXN]; int x[MAXN]; //临时解 int cost = 0; //临时解的成本 int bestx[MAXN]; //最优解 int mincost = INF; //最优解的成本 bool worker[MAXN]; //worker[j]表示任务j是否已经分配人员 void allocate(int i) //为第i个人员分配任务 { if (i > n) //到达叶子节点 { if (cost < mincost) { mincost = cost; for (int j = 1; j <= n; j++) bestx[j] = x[j]; } } else { for (int j = 1; j <= n; j++) { //为人员i试探任务j分配情况,从1到n if (!worker[j]) //任务j还没分配 { worker[j] = true; x[i] = j; //任务j分配给i人员 cost += c[i][j]; allocate(i + 1); //为人员i+1分配任务 worker[j] = false; //回溯 x[i] = 0; cost -= c[i][j]; } } } } int main() { memset(worker, 0, sizeof(worker)); cin >> n; for (int i = 1; i <=n; i++) for (int j = 1; j <= n; j++) cin >> c[i][j]; allocate(1); //从人员1开始尝试分配 printf("最优方案:\n"); for (int k = 1; k <= n; k++) { printf("第%d个人安排任务%d\n", k ,bestx[k]); } printf("总成本=%d\n", mincost); return 0; }
回溯算法求解任务分配问题中,每个人员试探1~n个任务,对应的解空间树是一颗n叉树,算法时间复杂度为:O(n^n)
这里采用队列式的分治限界法求解。
#include<iostream> #include<queue> using namespace std; #define INF 0x3f3f3f3f //定义无穷大 #define MAXN 21 int n; int c[MAXN][MAXN]; //人员任务-成本矩阵 int bestx[MAXN]; //最优分配方案 int mincost = INF; //最小成本 int total = 1; //结点个数累计 struct NodeType //队列结点类型 { int no; //结点编号 int i; //人员编号 int x[MAXN]; //x[i]为人员i分配的任务编号 bool worker[MAXN]; //worker[i]=true表示任务i已经被分配 int cost; //当前已分配任务的总成本 int lb; //下界 bool operator<(const NodeType& s) const //重载<关系函数> { return lb > s.lb; } }; void bound(NodeType& e) { //求结点e的界限值 int minsum = 0; for (int i = e.i + 1; i <= n; i++) { //求e[e.i+1...n]行中的最小元素 int minc = INF; for (int j = 1; j <= n; j++) if (e.worker[j] == false && c[i][j] < minc) minc = c[i][j]; minsum += minc; } e.lb = e.cost + minsum; } void bfs() { int j; NodeType e, e1; priority_queue<NodeType>qu; memset(e.x, 0, sizeof(e.x)); //初始化根节点的x值 memset(e.worker, 0, sizeof(e.worker)); //初始化根节点的worker e.i = 0; e.cost = 0; bound(e); //求根节点的lb e.no = total++; qu.push(e); //根节点进队列 while (!qu.empty()) { e = qu.top(); qu.pop(); //弹出队列结点e,当前考虑人员e.i if (e.i == n) { //比较求最优解 if (e.cost < mincost) { mincost = e.cost; for (j = 1; j <= n; j++) bestx[j] = e.x[j]; } } e1.i = e.i + 1; //拓展分配下一个人员的任务,对应结点e1 for (j = 1; j <= n; j++) { //考虑n个任务 if (e.worker[j]) //任务j是否已经分配人员,若已分配则跳过 continue; for (int i = 1; i <= n; i++) { e1.x[i] = e.x[i]; } e1.x[e1.i] = j; //为人员e1.i分配任务j for (int k = 1; k <= n; k++) { e1.worker[k] = e.worker[k]; } e1.worker[j] = true; //表示任务j已经分配 e1.cost = e.cost + c[e1.i][j]; bound(e1); //求e1的lb e1.no = total++; if (e1.lb <= mincost) //剪枝 qu.push(e1); } } } int main() { cout << "输入人员数/任务数的大小:n" << endl; cin >> n; cout << "输入人员-任务成本值("<<n<<"x"<<n<<"矩阵):" << endl; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { cin >> c[i][j]; } } bfs(); printf("最优方案:\n"); for (int k = 1; k <= n; k++) printf("第%d个人员分配第%d个任务\n",k, bestx[k]); cout <<"总成本="<< mincost; return 0; }
分支限界算法求解任务分配问题的时间复杂度为:O(n^n)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。