zoukankan      html  css  js  c++  java
  • 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
    ", 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.
    ", 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 }
    他坐在湖边,望向天空,她坐在对岸,盯着湖面
  • 相关阅读:
    Laravel 5.2 使用 JWT 完成多用户认证 | Laravel China 社区
    (上线时清缓存)laravel 5.1 的程序性能优化(配置文件)
    linux计划任务及压缩归档
    用户及用户管理
    vim编辑器
    linux进阶命令
    权限管理
    linux基础命令2
    linu基础命令1
    连接Xshell
  • 原文地址:https://www.cnblogs.com/Inkblots/p/5370339.html
Copyright © 2011-2022 走看看