Nov 7

Kruskal贪心算法求最小生成树 不指定

felix021 @ 2009-11-7 02:35 [IT » 程序设计] 评论(1) , 引用(0) , 阅读(7140) | Via 本站原创 | |
#include <stdio.h>
#include <stdlib.h>

/*
* Kruskal贪心算法求最小生成树(heap+并查集)
* 测试输入数据:

6 10 //6个顶点10条边
1 5 2  //从顶点1到顶点5的边权重为2
2 4 3
4 5 1
0 3 6
2 3 7
5 2 6
4 0 7
1 3 5
1 2 4
3 5 9

*/

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

void siftdown (struct edge *a, int n, int i) {
    struct edge t;
    if (i < 1 || i > n) return;
    while (i * 2 <= n) {
        i *= 2;
        if (i + 1 <= n && a[i].weight > a[i + 1].weight) i++;
        if (a[i].weight < a[i/2].weight ) {
            t = a[i];
            a[i] = a[i/2];
            a[i/2] = t;
        }
        else {
            break;
        }
    }
}

void siftup (struct edge *a, int n, int i) {
    struct edge t;
    if (i < 1 || i > n) return;
    while (i > 1) {
        if (a[i].weight < a[i/2].weight) {
            t = a[i];
            a[i] = a[i/2];
            a[i/2] = t;
        }
        else {
            break;
        }
        i /= 2;
    }
}

void makeheap(struct edge *a, int n) {
    int i;
    for (i = n / 2; i >= 1; --i) {
        siftdown(a, n, i);
    }
}

struct edge pop(struct edge *a, int *n) {
    struct edge t;
    t = a[1];
    a[1] = a[*n];
    (*n)--; //第二次挂在这里,不能写*n--(*n; n-=1;), 要写(*n)--
    siftdown(a, *n, 1);
    return t;
}

void dump(struct edge *a, int n) {
    int i;
    for (i = 0; i < n; ++i) {
        printf("edge (%d, %d), %d\n", a[i].start, a[i].end, a[i].weight);
    }
}

void initUnionSet(int a[], int n) {
    int i;
    for (i = 0; i < n; ++i) {
        a[i] = i;
    }
}

int getFather(int a[], int x) {
    return a[x] == x ? x : (a[x] = getFather(a, a[x]));
}

void merge(int a[], int x, int y) {
    x = getFather(a, x);
    y = getFather(a, y);
    a[x] = y;
}

int haveCommonAncestor(int a[], int x, int y) {
    return (getFather(a, x) == getFather(a, y) ? 1 : 0);
}


int main () {
    int m, n, i, k, *father;
    struct edge *input, *output, t;

    scanf("%d%d", &m, &n);
    input = (struct edge *)malloc(sizeof(struct edge) * (n + 1));
    for (i = 1; i <= n; ++i) {
        scanf("%d%d%d", &input[i].start, &input[i].end, &input[i].weight);
    }
    makeheap(input, n);
    dump(input+1, n);
    printf("end input\n");
    
    int n1 = n;
    output = (struct edge *)malloc(sizeof(struct edge) * (m - 1));
    father = (int *)malloc(sizeof(int) * n);
    initUnionSet(father, m);
    k = 0;
    printf("\nStart:\n");
    while (n1 > 0) {
        t = pop(input, &n1);
        printf("edge (%d,%d), %d ", t.start, t.end, t.weight);
        if (0 == haveCommonAncestor(father, t.start, t.end)) {
            printf("added in\n");
            output[k] = t;
            k++;
            merge(father, t.start, t.end);
            if (k == m - 1) {
                printf("~~ok~~\n");
                break;
            }
        }
        else {
            printf("ignored\n");
        }
    }
    printf("\nresult:\n");
    dump(output, k);

    free(input);
    free(output);
    free(father);
    return 0;
}


注:下面这段代码是之前写的,写了一个简单的链表+插入来实现,本来是想用队列式链表然后再排序的,但是太麻烦了,干脆直接插入排序,所以那个tail也就一点用也没有了(用在tree那个list里看起来还更NC)。其实更好的办法应该是根据输入的n动态分配足够的空间,全部输入以后然后用heap或者用qsort。


#include <stdio.h>
#include <stdlib.h>

/*
* Kruskal贪心算法求最小生成树
* 测试输入数据:
    6 10 //6个顶点10条边
    1 5 2  //从顶点1到顶点5的边权重为2
    2 4 3
    4 5 1
    0 3 6
    2 3 7
    5 2 6
    4 0 7
    1 3 5
    1 2 4
    3 5 9
*/

//链表
struct edge {
    int start, end, weight;
    struct edge *next;
};

struct linklist {
    struct edge *head, *tail;
};


void initLinkList(struct linklist *p) {
    p->head = (struct edge *) malloc(sizeof(struct edge));
    p->head->next = NULL;
    p->tail = p->head;
}

void insert(struct linklist *p, struct edge e) {
    struct edge *q = p->head, *t;
    while (q->next != NULL) {
        if (q->next->weight > e.weight) {
            break;
        }
        q = q->next;
    }
    t = (struct edge *) malloc(sizeof(struct edge));
    *t = e;
    t->next = q->next;
    q->next = t;
    if (t->next == NULL) {
        p->tail = t;
    }
}

void dump(struct linklist *p) {
    struct edge *q = p->head->next;
    while (q != NULL) {
        printf("q = %p, ", q);
        printf("edge (%d, %d), %d\n", q->start, q->end, q->weight);
        q = q->next;
    }
}

//并查集
void initUnionSet(int a[], int n) {
    int i;
    for (i = 0; i < n; ++i) {
        a[i] = i;
    }
}

int getFather(int a[], int x) {
    if (a[x] == x) {
        return x;
    }
    else {
        a[x] = getFather(a, a[x]);
        return a[x];
    }
}

void merge(int a[], int x, int y) {
    x = getFather(a, x);
    y = getFather(a, y);
    a[x] = y;
}

int haveCommonAncestor(int a[], int x, int y) {
    return (getFather(a, x) == getFather(a, y) ? 1 : 0);
}

int main () {
    int m, n; //m点,n边
    int i;
    struct linklist edges, tree;
    struct edge t;
    int father[1000];
    initLinkList(&edges);
    initLinkList(&tree);

    scanf("%d%d", &m, &n);
    for (i = 0; i < n; ++i) {
        scanf("%d%d%d", &t.start, &t.end, &t.weight);
        insert(&edges, t);
    }
    printf("Input:\n");
    dump(&edges);

    struct edge *p = edges.head->next;
    printf("\nBuilding tree...\n");
    initUnionSet(father, m);
    int count = 0;
    while (p != NULL) {
        printf("p = %p, ", p);
        printf("edge (%d, %d), %d: ", p->start, p->end, p->weight);
        if (0 == haveCommonAncestor(father, p->start, p->end)) {
            printf("added in.\n");
            insert(&tree, *p);
            merge(father, p->start, p->end);
            count++;
            printf("count = %d\n", count);
            if (count == m - 1) {
                break;
            }
        }
        else {
            printf("ignored.\n");
        }
        p = p->next;
    }

    printf("\nFinal result:\n");
    dump(&tree);
    return 0;
}




欢迎扫码关注:




转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php
Me999 Email Homepage
2009-11-7 08:03
这好像许多数据结构书上都有。
不过还是Prim用的多
felix021 回复于 2009-11-11 08:48
嗯 只是一个简单的实现练练手而已。

p.s. 其实还是Kruskal用得多。
分页: 1/1 第一页 1 最后页
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   *非必须
网址   电邮   [注册]