您的位置:首页 > 编程语言 > Go语言

Stanford - Algorithms: Design and Analysis, Part 2 - Week 1 Assignment: Greedy and Prim

2015-04-22 07:28 1506 查看
本次作业是正式引入greedy思想。。

greedy中比较典型的算法包括之前讲过的Dijkstra,本节课讲的prim以及下节课要讲的Kruskal

本次作业第一题和第二题基本是一个意思,一起讲:


Question 1

In this programming problem and the next you'll code up the greedy algorithms from lecture for minimizing the weighted sum of completion times.. Download the text file here.
This file describes a set of jobs with positive and integral weights and lengths. It has the format
[number_of_jobs]

[job_1_weight] [job_1_length]

[job_2_weight] [job_2_length]

...

For example, the third line of the file is "74 59", indicating that the second job has weight 74 and length 59. You should NOT assume that edge weights or lengths are distinct.
Your task in this problem is to run the greedy algorithm that schedules jobs in decreasing order of the difference (weight - length). Recall from lecture that this algorithm is not always optimal.
IMPORTANT: if two jobs have equal difference (weight - length), you should schedule the job with higher weight first. Beware: if you break ties in a different way, you are likely to get the wrong answer. You should report the sum of weighted completion times
of the resulting schedule --- a positive integer --- in the box below.
ADVICE: If you get the wrong answer, try out some small test cases to debug your algorithm (and post your test cases to the discussion forum)!


Question 2

For this problem, use the same data set as in the previous problem. Your task now is to run the greedy algorithm that schedules jobs (optimally) in decreasing order of the ratio (weight/length). In this algorithm, it does not matter how you break ties. You
should report the sum of weighted completion times of the resulting schedule --- a positive integer --- in the box below.

这两道题都算是比较简单的,就是按两种标准schedule job,然后算不同标准schedule后的完成时间。。

先上传下课上的课件说明下本题的背景:







Q1是按difference排序(即weight - length):

代码如下:

bool my_compare_1(job job1, job job2) {
	int diff1 = job1.weight - job1.len;
	int diff2 = job2.weight - job2.len;
	if (diff1 > diff2)
		return true;
	else if (diff1 < diff2)
		return false;
	else
		return (job1.weight > job2.weight);
}
Q2是按ratio排序(即weight/length):

代码如下:

bool my_compare_2(job job1, job job2) {
	double ratio1 = 1.0 * job1.weight / job1.len;
	double ratio2 = 1.0 * job2.weight / job2.len;
	if (ratio1 > ratio2)
		return true;
	else if (ratio1 < ratio2)
		return false;
	else
		return (job1.weight > job2.weight);
}
代码的使用也很直接,我是用C++写的,直接用的C++标准库里面自带的排序函数:

sort(joblist.begin(), joblist.end(), my_compare_1);
本题并没有太多好说的,直接上传完整代码吧:

# include <iostream>
# include <string>
# include <fstream>
# include <vector>
# include <algorithm>

using namespace std;

struct job {
int len;
int weight;
};
vector<job> joblist;

void store_file(string);
void print_all(void);
bool my_compare_1(job, job);
bool my_compare_2(job, job);
long complete_time(void);

int main(int argc, char** argv) {
store_file("jobs.txt");
sort(joblist.begin(), joblist.end(), my_compare_1);
long t = complete_time();
cout << "(diff version)Complete time: " << t << endl;

sort(joblist.begin(), joblist.end(), my_compare_2);
t = complete_time();
cout << "(ratio version)Complete time: " << t << endl;
return 0;
}

void store_file(string filename) {
ifstream infile;
infile.open(filename, ios::in);
int sz;
infile >> sz;
joblist.resize(sz);
int tmp_l, tmp_w;
for (int i = 0; i < sz; ++i) {
infile >> tmp_w >> tmp_l;
joblist[i].weight = tmp_w;
joblist[i].len = tmp_l;
}
infile.close();
}

void print_all(void) {
for (int i = 0; i < joblist.size(); ++i)
cout << joblist[i].weight << " " << joblist[i].len << endl;
cout << endl;
}

bool my_compare_1(job job1, job job2) { int diff1 = job1.weight - job1.len; int diff2 = job2.weight - job2.len; if (diff1 > diff2) return true; else if (diff1 < diff2) return false; else return (job1.weight > job2.weight); }

bool my_compare_2(job job1, job job2) { double ratio1 = 1.0 * job1.weight / job1.len; double ratio2 = 1.0 * job2.weight / job2.len; if (ratio1 > ratio2) return true; else if (ratio1 < ratio2) return false; else return (job1.weight > job2.weight); }

long complete_time(void) {
long t = 0;
int start = 0;
int finish;
for (int i = 0; i < joblist.size(); ++i) {
finish = start + joblist[i].len;
t += finish * joblist[i].weight;
start = finish;
}
return t;
}


然后是第三题:


Question 3

In this programming problem you'll code up Prim's minimum spanning tree algorithm. Download the text filehere. This
file describes an undirected graph with integer edge costs. It has the format
[number_of_nodes] [number_of_edges]

[one_node_of_edge_1] [other_node_of_edge_1] [edge_1_cost]

[one_node_of_edge_2] [other_node_of_edge_2] [edge_2_cost]

...

For example, the third line of the file is "2 3 -8874", indicating that there is an edge connecting vertex #2 and vertex #3 that has cost -8874. You should NOT assume that edge costs are positive, nor should you assume that they are distinct.
Your task is to run Prim's minimum spanning tree algorithm on this graph. You should report the overall cost of a minimum spanning tree --- an integer, which may or may not be negative --- in the
box below.
IMPLEMENTATION NOTES: This graph is small enough that the straightforward O(mn) time implementation of Prim's algorithm should work fine. OPTIONAL: For those of you seeking an additional challenge,
try implementing a heap-based version. The simpler approach, which should already give you a healthy speed-up, is to maintain relevant edges in a heap (with keys = edge costs). The superior approach stores the unprocessed vertices in the heap, as described
in lecture. Note this requires a heap that supports deletions, and you'll probably need to maintain some kind of mapping between vertices and their positions in the heap.

prim算法和Dijkstra算法十分相似,课件可以很好的解释Prim算法的过程:



其中有一步是选出u属于X,v不属于X的最小边,在这里选择binary heap这种数据结构会优化时间复杂度,说明如下:



具体代码实现的步骤就是先构造一个min heap,代码如下:

/* step1: construct the min heap */
	vector<heap_struct> min_heap(u_graph.size(), heap_struct());
	auto it = u_graph.begin();
	heap_struct h = {it->first, 0};
	min_heap[0] = h;
	++it;
	int i = 1;
	for (; it != u_graph.end(); ++it, ++i) {
		h = {it->first, INT_MAX};
		min_heap[i] = h;
	}
	make_heap(min_heap.begin(), min_heap.end(), Comp());
然后,只要这个min heap不为空,则取出最小的vertex u,然后寻找所有的u-v,看看哪个v是仍在min heap里面的,更新这些v的值,代码实现如下:

</pre><pre name="code" class="cpp">	while (!min_heap.empty()) {	
		int ver = min_heap[0].vertex;
//		cout << min_heap[0].key << endl;
		cost += min_heap[0].key;
		pop_heap(min_heap.begin(), min_heap.end(), Comp());
		min_heap.pop_back();
		for (int i = 0; i < u_graph[ver].size(); ++i) {
			int target = u_graph[ver][i].end;
			for (auto iter = min_heap.begin(); iter != min_heap.end(); ++iter) {
				if (iter->vertex == target) {
					if (iter->key > u_graph[ver][i].weight) {
						iter->key = u_graph[ver][i].weight;
						make_heap(min_heap.begin(), min_heap.end(), Comp());
					}
				}
			}
		}
	}
本题的完整代码如下:

# include <iostream>
# include <fstream>
# include <vector>
# include <algorithm>
# include <unordered_map>
# include <climits>

using namespace std;

struct edge{
int start;
int end;
int weight;
};

struct heap_struct {
int vertex;
int key;
};

struct Comp {
bool operator()(const heap_struct& h1, const heap_struct& h2) {
return h1.key > h2.key;
}
};

unordered_map<int, vector<edge>> u_graph;

void store_file(string);
void print_all(void);
long prim(void);

int main(int argc, char** argv) {
store_file("edges.txt");
// print_all();
long cost = prim();
cout << "Cost: " << cost << endl;
return 0;
}

void store_file(string filename) {
ifstream infile;
infile.open(filename, ios::in);
int vertices;
int edges;
infile >> vertices >> edges;
int s, e;
int w;
while (edges > 0) {
infile >> s >> e >> w;
if (u_graph.find(s) == u_graph.end())
u_graph.insert(pair<int, vector<edge>>(s, vector<edge>()));
if (u_graph.find(e) == u_graph.end())
u_graph.insert(pair<int, vector<edge>>(e, vector<edge>()));
edge e1 = {s, e, w};
edge e2 = {e, s, w};
u_graph[s].push_back(e1);
u_graph[e].push_back(e2);
--edges;
}
infile.close();
}

void print_all(void) {
for (auto it = u_graph.begin(); it != u_graph.end(); ++it) {
cout << it->first << ": ";
for (int i = 0; i < it->second.size(); ++i)
cout << "(" << it->second[i].start << ", " << it->second[i].end << ", "
<< it->second[i].weight << ")";
cout << endl;
}
}

long prim(void) {
/* step1: construct the min heap */ vector<heap_struct> min_heap(u_graph.size(), heap_struct()); auto it = u_graph.begin(); heap_struct h = {it->first, 0}; min_heap[0] = h; ++it; int i = 1; for (; it != u_graph.end(); ++it, ++i) { h = {it->first, INT_MAX}; min_heap[i] = h; } make_heap(min_heap.begin(), min_heap.end(), Comp());

/* while min_heap is not empty, do following:
* a)extract min value from min heap, let the extracted value be u
* b)for every adjacency vertex v of u, check if v is in the min heap,
* if v in min heap and its key value is more than weight of u-v, then
* update the key value of v as weight of u-v */
long cost = 0;
while (!min_heap.empty()) {
int ver = min_heap[0].vertex;
// cout << min_heap[0].key << endl;
cost += min_heap[0].key;
pop_heap(min_heap.begin(), min_heap.end(), Comp());
min_heap.pop_back();
for (int i = 0; i < u_graph[ver].size(); ++i) {
int target = u_graph[ver][i].end;
for (auto iter = min_heap.begin(); iter != min_heap.end(); ++iter) {
if (iter->vertex == target) {
if (iter->key > u_graph[ver][i].weight) {
iter->key = u_graph[ver][i].weight;
make_heap(min_heap.begin(), min_heap.end(), Comp());
}
}
}
}
}
return cost;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: