POJ 1278 Agri-Net 最小生成树模板题(Prim 与 Kruskal)

这是我的第一篇oj记录博文,请大家以后多多指教。今天本来想做poj 3241曼哈顿最小生成树的那道题,结果学了半天发现自己连Kruskal都不能正确实现,所以就回来重刷了一下最小数模板题的此题,并之前的prim算法的解法的代码一起发出。

Prim与Kruskal算法都是求解最小生成树的有效方法,但是两者的高效实现都依赖于巧妙的数据结构。Kruskal算法如果借助于并查集,则能达到O(E*alpha(E))的求解时间(其中alpha函数是一个增长及其缓慢的函数,在这里可以视为是常数),另外加上排序的时间,总时间为O(E log(E) ); 而prim算法中要维护一个最小优先队列,而且要求能在O(1)时间内查找元素并改变它的值,我暂时没有了解到很好的方法,而二叉堆的查找元素时间还是O(n)的,所以还不如直接用数组维护。

poj 1278题面在此不再赘述,就是一道顶点数<100的最小生成树的题目。以下附上个人代码。编程习惯用camelVariant命名法,另外变量名较长,请多担待。

Prim方法:

#include 
#include 
#define Size 101

typedef int iter;
int farms[Size][Size];
struct Vertex {
	int key;
	int piNumber;
	bool isValid;
};
typedef struct Vertex Vertex;
Vertex vertices[Size];
int extractMin(int size) 
{
	int isNull = true;
	int tempMin = INT_MAX;
	int tempMinIndex = -1;
	for (int i = 0; i < size; i++) {
		if (!vertices[i].isValid)
			continue;
		else {
//			printf("Here.\n");
			isNull = false;
			if (tempMin > vertices[i].key) {
				tempMinIndex = i;
				tempMin = vertices[i].key;
			}
		}
	}
//	printf("TempMinIndex:%d\n", tempMinIndex);
	if (!isNull) {
		vertices[tempMinIndex].isValid=false;
	}
	return tempMinIndex;
}
bool isBeLong(int size,int checkNumber)
{
	return vertices[checkNumber].isValid && size > checkNumber;
}
int main()
{
	iter i, j, k;
	int size,temp;
	while (scanf("%d", &size) != EOF) {
		for (i = 0; i < size; i++)
			for (j = 0; j < size; j++)
				scanf("%d", &farms[i][j]);
/*		for (i = 0; i < size; i++) {
			for (j = 0; j < size; j++) {
				printf("%d", farms[i][j]);
				j == size - 1 ? printf("\n") : printf("\t");
			}
		}*/
		
		for (i = 0; i < size; i++) {
			vertices[i].piNumber = -1;
			vertices[i].key =1000000;
			vertices[i].isValid = true;
		}
		temp = extractMin(size);
		while (temp >= 0) {
//			printf("Temp:%d\n", temp);
			for (i = 0; i < size; i++) {
				if (i != temp) {
					if (farms[temp][i] < vertices[i].key&&isBeLong(size, i)) {
						vertices[i].piNumber = temp;
						vertices[i].key = farms[temp][i];
					}
				}
			}
			temp = extractMin(size);
		}
		int value = 0;
		for (int i = 0; i < size; i++)
			value += farms[i][vertices[i].piNumber];
		printf("%d\n", value);
	}
	return 0;
}


Kruskal方法:


#include 
#include 
#include 
#include 
#include 
using namespace std;

struct Edge {
	int from;
	int to;
	int weight;
	bool operator < (const Edge& ele) {
		return this->weight < ele.weight;
	}
};
typedef struct Edge Edge;

class KruskalGraph
{
public:
	void init(int n)
	{
		this->edges.clear();
		this->vertices.clear();
		for (int i = 0; i < n; i++)
			this->vertices.push_back(-1);
		this->treeEdges.clear();
		this->order = n;
	}
	void Inserto(int u, int v, int w)
	{
		Edge tempEdge;
		tempEdge.from = u;
		tempEdge.to = v;
		tempEdge.weight = w;
		this->edges.push_back(tempEdge);
	}
	void Kruskal()
	{
		sort(edges.begin(), edges.end());
		int count = 0;
		for (int i = 0; i < edges.size()&&counttreeEdges.push_back(edges[i]);
				Union(root1, root2);
				count++;
			}
		}
	}
	void showMST()
	{
		for (int i = 0; i < treeEdges.size(); i++) {
			printf("(%d,%d,%d) ", treeEdges[i].from, treeEdges[i].to, treeEdges[i].weight);
		}
		printf("\n");
	}
	int mstValu()
	{
		int ret = 0;
		for (int i = 0; i < treeEdges.size(); i++)
			ret += treeEdges[i].weight;
		return ret;
	}
private:
	vector edges;
	vector treeEdges;
	vector vertices;
	int order;
	void Union(int x, int y)
	{
		int root1, root2;
		root1 = Find(x);
		root2 = Find(y);
		//printf("Roots:%d %d\n", root1, root2);
		_union(root1, root2);
	}
	int Find(int x)
	{
		if (vertices[x] < 0)
			return x;
		else
			return vertices[x] = Find(vertices[x]);
	}
	void _union(int x, int y)
	{
		if (vertices[y] < vertices[x]) {
			vertices[x] = y;
		}
		else {
			if (vertices[x] == vertices[y])
				vertices[x]--;
			vertices[y] = x;
		}
	}
};
int main()
{
	int n;
	KruskalGraph graph;
	while (scanf("%d", &n) != EOF) {
		graph.init(n);
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				int weight;
				scanf("%d", &weight);
				if (i > j)
					graph.Inserto(i, j, weight);
			}
		}
		graph.Kruskal();
		//graph.showMST();
		printf("%d\n", graph.mstValu());
	}
	return 0;
}

另外附上今天学习到的两个模板:

一个并查集的:

class UnionFindSet : vector
{
public:
	UnionFindSet(int k)
	{
		this->clear();
		for (int i = 0; i < k; i++) {
			this->push_back(-1);
		}
	}
	void show()
	{
		for (int i = 0; i < this->size(); i++) {
			printf("%d ", (*this)[i]);
		}
		printf("\n");
	}
	int find(int x)
	{
		if ((*this)[x] < 0)
			return x;
		else
			return (*this)[x] = find((*this)[x]);
	}
	void Union(int x, int y)
	{
		int root1, root2;
		root1 = find(x);
		root2 = find(y);
		printf("Roots:%d %d\n", root1, root2);
		_union(root1, root2);
	}
private:
	void _union(int x, int y)
	{
		if ((*this)[y] < (*this)[x]) {
			(*this)[x] = y;
		}
		else {
			if ((*this)[x] == (*this)[y])
				(*this)[x]--;
			(*this)[y] = x;
		}
	}
};

另外一个别人的Binary Indexed Tree的,先学着,看明天做曼哈顿树的那道题的时候用不用的上

class BinTree : vector
{
public:
	explicit BinTree(int k = 0) {
		assign(k + 1, 0);
	}
	int sum(int k)
	{
		return k > 0 ? sum(k - lowBit(k)) + (*this)[k] : 0;
	}
	int last()
	{
		return size() - 1;
	}
	void add(int k, int w)
	{//for adding w to node k
		if (k > last())
			return;
		(*this)[k] += w;
		add(k + lowBit(k), w);
	}
	void show(int start, int end)
	{
		for (int i = start; i <= end; i++) {
			printf("%d ", (*this)[i]);
		}
		printf("\n");
	}
	void show()
	{
		for (int i = 0; i < this->size(); i++) {
			printf("%d ", (*this)[i]);
		}
		printf("\n");
	}
private:
	int lowBit(int k)
	{
		return k&-k;
	}
};

今天就写到这里。上述有些技术细节我以后写文过程中有空的时候会提及。以后还请多关照了。

你可能感兴趣的:(oj,odyssey)