1. 题目1:关于工作安排, 每个工作有权重weight和时长length这样两个属性,要求如何安排时间使得$\sum_j^n W_j C_j$的值最小。假设一共n个工作,$W_j$为第j个工作的权重,$C_j$为到第j个工作工作完成的时长(加上之前的工作时长)。
贪心算法有这样两个思路: 按照 (1) weight-length 和 (2)weight/length 的从大到小的思路进行排列,故可以用到优先队列。
1.1 优先队列按照存储工作的weight-length的从大到小的属性排列,按照从大到小的值对$\sum_j^n W_j C_j $进行计算。代码如下
#include <iostream> #include <vector> #include <sstream> #include <fstream> #include <stack> #include <queue> #include <algorithm> using namespace std; class Job { public: int index; //工作号 int weight; //权重 int length; //工作时长 int we_le; //weight-length }; /***********优先队列Job类自定义比较函数**********/ class mycompare { bool reverse; public: mycompare(const bool & re = false) {reverse = re;} bool operator() (Job &a, Job &b) const { if(reverse) return (a.we_le > b.we_le);//实现从小到大的排列 else { if(a.we_le == b.we_le) { return (a.weight < b.weight); // 如果相等,则选择weight大的排在前 } else { return (a.we_le < b.we_le); //从大到小 } } } }; /*************工作安排*******************/ class JobShedule { public: JobShedule() { ifstream fin("t.txt"); string line; stringstream stream; if(getline(fin,line)) { stream.clear(); stream << line; stream >> count; } int cnt = 0; while(getline(fin, line)) { int _len, _wei; stream.clear(); stream << line; stream >> _wei; stream >> _len; jobs[cnt].index = cnt + 1; jobs[cnt].length = _len; jobs[cnt].weight = _wei; jobs[cnt].we_le = _wei - _len; mypq.push(jobs[cnt]); cnt++; } } /*************计算总的带权重的工作时间**************/ void calc_time() { ofstream fout; fout.open("output.txt"); while(!mypq.empty()) { Job tmp = mypq.top(); mypq.pop(); curLength += tmp.length; time += tmp.weight * curLength; fout << "tmp time:: " << time << endl; } } public: int count; long long time = 0; int curLength = 0; Job jobs[12]; //优先队列,按照工作的weight-length排列队列。 priority_queue <Job, vector< Job > ,mycompare> mypq; }; int main() { JobShedule jobsh; jobsh.calc_time(); cout << "total time:" << jobsh.time << endl; return 0; }
1.2 如果按照工作的weight/length从大到小排列。
class Job { public: int index; int weight; int length; float ratio; //按照weight/length }; /*************自定义比较函数,按照ratio从大到小排列***************/ class mycompare { bool reverse; public: mycompare(const bool & re = false) {reverse = re;} bool operator() (Job &a, Job &b) const { if(reverse) return (a.ratio > b.ratio);//实现从小到大的排列 else { if(a.ratio == b.ratio) { return (a.weight < b.weight); // 如果相等,则选择weight大的排在前 } else { return (a.ratio < b.ratio); //从大到小 } } } };
2.prim算法的简单实现,代码比较烂。对cost的最小值进行选取。
#include <iostream> #include <string> #include <stack> #include <fstream> #include <sstream> #include <ctime> #include <vector> #include <queue> #include <algorithm> using namespace std; /**********边表************/ class EdgeNode { public: int adjvex; int cost; int head; EdgeNode *next; EdgeNode(int _head, int _adj, int _cost,EdgeNode *n = NULL) : head(_head), adjvex(_adj), cost(_cost), next(n) {} }; /*=========顶点表============*/ class VertexNode { public: int data; EdgeNode *firstEdge; VertexNode() { firstEdge = NULL; } }; /*********自定义比较函数(优先队列使用)************/ class mycompare { bool reverse; public: mycompare(const bool &re = true) { reverse = re; } bool operator() (EdgeNode *a, EdgeNode *b) const { //从小到大排列, 优先队列,!mycompare,按照cost的从小到大排列 if(reverse) return (a->cost > b->cost); else { return (a->cost < b->cost); //从小到大排列, 优先队列,!mycompare,按照cost的从大到小排列 } } }; /*********无向图的数据结构*************/ class Graph { public: /*********初始化图的邻接表数据***************/ Graph() { ifstream fin("pp.txt"); string line; stringstream stream; if(getline(fin, line)) { stream.clear(); stream << line; stream >> numVertexes; stream >> numEdges; } init_adjList(); while(getline(fin, line)) { int vertex, adjacent, _cost; stream.clear(); stream << line; stream >> vertex; stream >> adjacent; stream >> _cost; addEdge(vertex, adjacent, _cost); } } /********初始化邻接表的顶点表*******/ void init_adjList() { adjList.resize(numVertexes); for(int i = 0; i < numVertexes; i++) { adjList[i].data = i; } } /************加边,头插法*****************/ void addEdge(int a, int b, int _cost) { EdgeNode *enode1 = new EdgeNode(a-1, b-1, _cost, NULL); EdgeNode *enode2 = new EdgeNode(b-1, a-1, _cost, NULL); adjList[a-1].data = a-1; enode1->next = adjList[a-1].firstEdge; adjList[a-1].firstEdge = enode1; adjList[b-1].data = b-1; enode2->next = adjList[b-1].firstEdge; adjList[b-1].firstEdge = enode2; } /************打印看结果************/ void print() { ofstream fout; fout.open("primoutput.txt"); for(int i = 0; i < numVertexes; i++) { fout << "vertex:" << adjList[i].data << " adj:" ; EdgeNode *tmp = new EdgeNode(0, 0, 0 ); tmp = adjList[i].firstEdge; while(tmp) { fout << tmp->adjvex << "cost: " << tmp->cost << " "; tmp = tmp->next; } fout << endl; } } /*********************************/ public: int numVertexes; //顶点数目 int numEdges; //边数目 vector<VertexNode> adjList; //图的邻接表 }; /***********prim算法实现**********/ class Prims { public: Prims(Graph graph) { int s = 0; length = graph.numVertexes; //顶点数目 tree.resize(length); marked.push_back(s); //将初始顶点加入最小生成树中 pq.push(graph.adjList[s].firstEdge); //将初始顶点的第一条边加入队列 while(!pq.empty()) { EdgeNode *p = new EdgeNode(0,0,0); p = graph.adjList[s].firstEdge; while(p) { if(!is_marked(p->adjvex)) { pq.push(p); } p = p->next; } EdgeNode *p1 = new EdgeNode(0,0,0); p1 = pq.top(); pq.pop(); s = p1->adjvex; if(!is_marked(s)) //如果没有加入进最小生成树 { marked.push_back(p1->adjvex); tree[p1->head].push_back(p1->adjvex); //将边加入最小生成数 sum += p1->cost; //cost的累加 } } } /*******************判断是否加入最小生成树***************/ bool is_marked(int a) { for(int i = 0; i < marked.size(); i++) { if(marked[i] == a) { return true; } } return false; } /***************输出看结果**************/ void write() { ofstream fout; fout.open("tree.txt"); for(int i = 0; i < length; i++) { fout << "tree[" << i << "]: " ; for(int j = 0; j < tree[i].size(); j++) { fout << tree[i][j] << " "; } fout << endl; } } public: int length; int sum = 0; vector<int> marked;//最小生成树木的顶点表 vector<vector<int> > tree; //最小生成树的边 ,数组存储 priority_queue<EdgeNode*, vector<EdgeNode*>, mycompare> pq; //优先队列 }; int main() { Graph graph; graph.print(); Prims _prims(graph); _prims.write(); cout << "sum: " << _prims.sum << endl; return 0; }