最小生成树--->NYOJ-38 布线问题

此题是最基础的最小生成树的题目,有两种方法, 一个是prim一个是kruskal算法,前者利用邻接矩阵,后者是利用边集数组

prim算法的思想是:一个点一个点的找, 先找从第一个点到其他点最小的, 把权值存放到一个lowcost的数组中,然后继续找下一个点,然后更新lowcost数组,注意,这时的lowcost不完全是第二个点到所有点的距离,而是,其他点到最小生成树的距离,然后一步一步的求,知道求完所有点

kruskal算法的思想是:先把边集数组按照权值进行排序,之后从最小的往上找,这时有个前提,就是不能有环,这样就能保证最大连通量为1,借助father数组

代码如下:

方法一(Prim):

 

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 const int MAX = 500 + 10;
 6 const int INFINITY = 999999;
 7 int map[MAX][MAX];
 8 int Sum;
 9 int v, e;//v来存点的个数,e来存边的个数 
10 void mini_span_tree_prim()
11 {
12     int lowcost[MAX];
13     lowcost[1] = 0;//标记已经加到最小生成树中 
14     for(int i = 2; i <= v; i++)
15     {
16         lowcost[i] = map[1][i];
17     }
18     for(int i = 2; i <= v; i++)
19     {
20         int j = 2;
21         int index = 1;
22         int minweight = INFINITY;
23         while(j <= v)
24         {//找出最小的边来,并保存其坐标 
25             if(lowcost[j] != 0 && lowcost[j] < minweight)
26             {
27                 minweight = lowcost[j];
28                 index = j;
29             }
30             j++;
31         }
32         lowcost[index] = 0;//标记已经加到最小生成树中 
33         Sum += minweight;
34         for(j = 2; j <= v; j++)
35         {//判断没有加到最小生成树中的和比当前权值要小的点 
36             if(lowcost[j] != 0 && lowcost[j] > map[index][j])
37             {
38                 lowcost[j] = map[index][j];
39             }
40         }
41     }
42 }
43 int main()
44 {
45     //freopen("1.txt", "r", stdin);
46     int n;
47     scanf("%d", &n);
48     while(n--)
49     {
50         Sum = 0;
51         scanf("%d %d", &v, &e);
52         int t1, t2, t3;
53         memset(map, 1, sizeof(map));
54         for(int i = 1; i <= v; i++)
55         {
56             map[i][i] = 0;
57         }
58         for(int i= 0; i < e; i++)
59         {
60             scanf("%d %d %d", &t1, &t2, &t3);
61             map[t1][t2] = t3;
62             map[t2][t1] = t3;
63         }
64         int mincost = INFINITY;
65         for(int i = 0; i < v; i++)
66         {
67             scanf("%d", &t1);
68             mincost = min(mincost, t1);
69         }
70         mini_span_tree_prim();
71         printf("%d\n", Sum + mincost);
72     }    
73     return 0;
74 } 

 

 

 

方法二(Kruskal):

#include <stdio.h>
#include <algorithm>
#include <cstring>
using namespace std;
typedef struct Node{
    int s;
    int e;
    int weight;
}Node;
const int MAX = 500 + 10;
const int INFINITY = 99999999;
Node arr[MAX * 250];
int father[MAX];
int sum;
int v, edges;

bool cmp(Node a, Node b)
{
    return a.weight < b.weight;
}

int find(int f)
{
    while(father[f] > 0)
        f = father[f];
    return f;
}
//生成最小生成树 
void mini_span_tree_kruskai()
{
    int n, m;
    int cnt = 0;
    for(int i= 0; i < edges; i++)
    {
        n = find(arr[i].s);
        m = find(arr[i].e);
        if(cnt == v - 1)//优化,如果找到了n-1条边,这时退出就行了 
            break;
        if(n != m)//判断是否构成了环 
        {
            father[m] = n;
            sum += arr[i].weight;
            cnt++;
        }
    }
}

int main()
{
    int n;
    scanf("%d", &n);
    while(n--)
    {
        memset(arr, 0, sizeof(arr));
        memset(father, 0, sizeof(father));
        sum = 0;
        scanf("%d %d", &v, &edges);
        for(int i = 0; i < edges; ++i)
        {
            scanf("%d %d %d", &arr[i].s, &arr[i].e, &arr[i].weight);
        }
        int mincost = INFINITY;
        int t;
        for(int i = 1; i <= v; i++)
        {
            scanf("%d", &t);
            mincost = min(mincost, t);
        }
        sort(arr, arr + edges, cmp);//排序 
    //    for(int i = 0; i < edges; i++)
//            printf("%d %d %d\n", arr[i].s, arr[i].e, arr[i].weight);
//        printf("%d\n", mincost);
        mini_span_tree_kruskai();
        printf("%d\n", sum + mincost);
        
    }        
    return 0;
}

 

posted @ 2014-11-08 18:24  Howe_Young  阅读(206)  评论(0编辑  收藏  举报