ACM/ICPC 之 Prim范例(ZOJ1586-POJ1789(ZOJ2158))

  两道Prim解法范例题型,简单的裸Prim,且两题相较以边为重心的Kruskal解法而言更适合以点为重心扩展的Prim解法。

 

 

 

ZOJ1586-QS Network

 

  题意:见Code

  题解:直接的MST题型,本题的图为稠密图,因此适合以点为扩展导向的Prim算法(代码量也较少)。

     大抵是先以某点A为中心,标记点A,访问其邻接点,更新全图到该点的距离(不通路以INF表示),找出最短距离的点B

     标记最短距离的B点,然后访问其邻接点,更新邻接点到B点的最短距离,找出最短距离的点C…以此类推…

     将已标记的点作为生成树M节点,此时M就是所求最小生成树。

     该算法的实际核心可以理解为每次更新所有未加入生成树M的点到集合M(将M理解为一个整体)的最短距离

     因此该算法普遍将该最短距离简化为一个数组,教材上一般命名为lowcost[MAX],不断更新此数组的最小值即可。

 

  

 1 //Prim-裸
 2 //建立QS网络,一条网线需要一定成本及两点处的适配器成本,求最小费用
 3 //本题的边数可到10^6,而点只到10^3,因此理论上说用prim比Kruskal明智(也比较好写)
 4 //Time:30Ms    Memory:4228K
 5 #include<iostream>
 6 #include<cstring>
 7 #include<cstdio>
 8 #include<algorithm>
 9 using namespace std;
10 
11 #define INF 0x3f3f3f3f
12 #define MAX 1005
13 
14 int n;
15 int d[MAX][MAX];
16 int adapter[MAX];    //适配器价格
17 int lowcost[MAX];    //各点到已生成集合的最小路长
18 bool v[MAX];    //已访问的点
19 
20 void prim()
21 {
22     memset(lowcost, INF, sizeof(lowcost));
23     memset(v, false, sizeof(v));
24     
25     int minv = 0;
26     v[0] = true;
27     for (int i = 1; i < n; i++)
28         lowcost[i] = d[i][0];
29     for (int i = 1; i < n; i++)
30     {
31         int mind = INF;
32         int k;    //最近的结点编号
33         for (int j = 0; j < n; j++)
34         {
35             if (!v[j] && mind > lowcost[j])
36             {
37                 mind = lowcost[j];
38                 k = j;
39             }
40         }
41         
42         minv += mind;
43         v[k] = true;
44         for (int j = 0; j < n; j++)
45             if(!v[j])    lowcost[j] = min(lowcost[j], d[k][j]);
46     }
47     printf("%d\n", minv);
48 }
49 
50 int main()
51 {
52     int T;
53     scanf("%d", &T);
54     while (T--)
55     {
56         scanf("%d", &n);
57         for (int i = 0; i < n; i++)
58             scanf("%d", &adapter[i]);
59         for (int i = 0; i < n; i++)
60             for (int j = 0; j < n; j++)
61             {
62                 scanf("%d", &d[i][j]);
63                 d[i][j] += adapter[i] + adapter[j];
64             }
65         prim();
66     }
67     return 0;
68 }

 

 

POJ1789(ZOJ2158)-Truck History

 

  题意:由7位编码组成的卡车编码,两个编码间的距离以对应位置的编码不同个数为总距离,例如aaaaaaa,abaabaa两个编码距离为2,求使得所有卡车编码最近的距离。(与实际题意有一点不同,为了方便理解稍微改编了一些)

  题解:理解了题意就好做了,本质依然是求一个裸的MST。

     Prim算法思路参照上题题解。

 

 1 //Prim-裸
 2 //POJ1789-ZOJ2158
 3 //边数4*10^6,点2000,稠密图较适合Prim
 4 //Time:657Ms    Memory:15872K
 5 #include<iostream>
 6 #include<cstring>
 7 #include<cstdio>
 8 #include<algorithm>
 9 using namespace std;
10 
11 #define INF 0x3f3f3f3f
12 #define MAX 2001
13 
14 int n;
15 int d[MAX][MAX];
16 int lowcost[MAX];
17 bool v[MAX];
18 char s[MAX][8];
19 
20 void prim()
21 {
22     memset(lowcost, INF, sizeof(lowcost));
23     memset(v, false, sizeof(v));
24     int minv = 0;
25     v[0] = true;
26     for (int i = 0; i < n; i++)
27         lowcost[i] = d[i][0];
28     for (int i = 1; i < n; i++)
29     {
30         int mind = INF;
31         int k;
32         for (int j = 0; j < n; j++)
33         {
34             if (!v[j] && mind > lowcost[j])
35             {
36                 mind = lowcost[j];
37                 k = j;
38             }
39         }
40         minv += mind;
41         v[k] = true;
42         for (int j = 0; j < n; j++)
43             if (!v[j]) lowcost[j] = min(lowcost[j], d[k][j]);
44     }
45     printf("The highest possible quality is 1/%d.\n", minv);
46 }
47 
48 int main()
49 {
50     while (scanf("%d", &n), n)
51     {
52         for (int i = 0; i < n; i++)
53             scanf("%s", s[i]);
54         memset(d, 0, sizeof(d));
55         for (int i = 0; i < n; i++)
56             for (int j = i+1; j < n; j++)
57                 for (int k = 0; k < 7; k++)
58                     d[j][i] = d[i][j] += s[i][k] != s[j][k];
59         prim();
60     }
61     return 0;
62 }

 

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/Inkblots/p/5370339.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞