这是我的第一篇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;
}
}
};
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;
}
};