zoukankan      html  css  js  c++  java
  • 最小生成树,POJ和HDU几道题目的解题报告(基于自己写的模板)

    首先POJ题目:

    链接:1251 Jungle Roads

    题目大意:纯求最小生成树,结果为最小权值边的和。采用邻接表

    代码:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <vector>
      4 #include <queue>
      5 using namespace std;
      6 
      7 #define maxn 30  //最大顶点个数
      8 int n;       //顶点数,边数
      9 
     10 struct arcnode  //边结点
     11 {
     12     int vertex;     //与表头结点相邻的顶点编号
     13     int weight;     //连接两顶点的边的权值
     14     arcnode * next; //指向下一相邻接点
     15     arcnode() {}
     16     arcnode(int v,int w):vertex(v),weight(w),next(NULL) {}
     17 };
     18 
     19 struct vernode      //顶点结点,为每一条邻接表的表头结点
     20 {
     21     int vex;    //当前定点编号
     22     arcnode * firarc;   //与该顶点相连的第一个顶点组成的边
     23 }Ver[maxn];
     24 
     25 void Init()  //建立图的邻接表需要先初始化,建立顶点结点
     26 {
     27     for(int i = 1; i <= n; i++)
     28     {
     29         Ver[i].vex = i;
     30         Ver[i].firarc = NULL;
     31     }
     32 }
     33 
     34 void Insert(int a, int b, int w)   //头插法,效率更高,但不能去重边
     35 {
     36     arcnode * q = new arcnode(b, w);
     37     if(Ver[a].firarc == NULL)
     38         Ver[a].firarc = q;
     39     else
     40     {
     41         arcnode * p = Ver[a].firarc;
     42         q->next = p;
     43         Ver[a].firarc = q;
     44     }
     45 }
     46 struct node     //保存key值的结点
     47 {
     48     int v;
     49     int key;
     50     friend bool operator<(node a, node b)   //自定义优先级,key小的优先
     51     {
     52         return a.key > b.key;
     53     }
     54 };
     55 
     56 #define INF 0xfffff    //权值上限
     57 int parent[maxn];   //每个结点的父节点
     58 bool visited[maxn]; //是否已经加入树种
     59 node vx[maxn];      //保存每个结点与其父节点连接边的权值
     60 priority_queue<node> q; //优先队列stl实现
     61 void Prim(int s)    //s表示根结点
     62 {
     63     for(int i = 1; i <= n; i++) //初始化
     64     {
     65         vx[i].v = i;
     66         vx[i].key = INF;
     67         parent[i] = -1;
     68         visited[i] = false;
     69     }
     70     vx[s].key = 0;
     71     q.push(vx[s]);
     72     while(!q.empty())
     73     {
     74         node nd = q.top();  //取队首,记得赶紧pop掉
     75         visited[nd.v] = true;
     76         q.pop();
     77         arcnode * p = Ver[nd.v].firarc;
     78         while(p != NULL)    //找到所有相邻结点,若未访问,则入队列
     79         {
     80             if(!visited[p->vertex] && p->weight < vx[p->vertex].key)
     81             {
     82                 parent[p->vertex] = nd.v;
     83                 vx[p->vertex].key = p->weight;
     84                 vx[p->vertex].v = p->vertex;
     85                 q.push(vx[p->vertex]);
     86             }
     87             p = p->next;
     88         }
     89     }
     90 }
     91 void Show()     //打印图的邻接表(有权值)
     92 {
     93     for(int i = 1; i <= n; i++)
     94     {
     95         cout << Ver[i].vex;
     96         arcnode * p = Ver[i].firarc;
     97         while(p != NULL)
     98         {
     99             cout << "->(" << p->vertex << "," << p->weight << ")";
    100             p = p->next;
    101         }
    102         cout << "->NULL" << endl;
    103     }
    104 }
    105 int main()
    106 {
    107     int k, d;
    108     char x, y;
    109     while(cin >> n && n!=0)
    110     {
    111         Init();
    112         for(int i = 1; i < n; i++)
    113         {
    114             cin >> x >> k;
    115             while(k--)
    116             {
    117                 cin >> y >> d;
    118                 Insert(x-'A'+1, y-'A'+1, d);
    119                 Insert(y-'A'+1, x-'A'+1, d);
    120             }
    121         }
    122         Prim(1);
    123         int ans = 0;
    124         for(int i = 1; i <= n; i++)
    125             ans += vx[i].key;
    126         printf("%d
    ", ans);
    127     }
    128     return 0;
    129 }

    链接:1258 Agri-Net

    题目大意:求最小生成树,邻接矩阵实现

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <queue>
     4 using namespace std;
     5 
     6 #define maxn 110
     7 #define INF 100020    //预定于的最大值
     8 int n;   //顶点数、边数
     9 int g[maxn][maxn];      //邻接矩阵表示
    10 
    11 struct node     //保存key值的结点
    12 {
    13     int v;
    14     int key;
    15     friend bool operator<(node a, node b)   //自定义优先级,key小的优先
    16     {
    17         return a.key > b.key;
    18     }
    19 };
    20 int parent[maxn];   //每个结点的父节点
    21 bool visited[maxn]; //是否已经加入树种
    22 node vx[maxn];      //保存每个结点与其父节点连接边的权值
    23 priority_queue<node> q; //优先队列stl实现
    24 void Prim(int s)    //s表示根结点
    25 {
    26     for(int i = 1; i <= n; i++) //初始化
    27     {
    28         vx[i].v = i;
    29         vx[i].key = INF;
    30         parent[i] = -1;
    31         visited[i] = false;
    32     }
    33     vx[s].key = 0;
    34     q.push(vx[s]);
    35     while(!q.empty())
    36     {
    37         node nd = q.top();  //取队首,记得赶紧pop掉
    38         q.pop();
    39         if(visited[nd.v] == true)   //深意,因为push机器的可能是重复但是权值不同的点,我们只取最小的
    40             continue;
    41         int st = nd.v;
    42         //cout << nd.v << " " << nd.key << endl;
    43         visited[nd.v] = true;
    44         for(int j = 1;  j <= n; j++)
    45         {
    46             if(j!=st && !visited[j] && g[st][j] < vx[j].key)    //判断
    47             {
    48                 parent[j] = st;
    49                 vx[j].key = g[st][j];
    50                 q.push(vx[j]);
    51 
    52             }
    53         }
    54     }
    55 }
    56 int main()
    57 {
    58     while(~scanf("%d", &n))
    59     {
    60         for(int i = 1; i <= n; i++)
    61             for(int j = 1; j <= n; j++)
    62             {
    63                 scanf("%d", &g[i][j]);
    64                 if(g[i][j] == 0)
    65                     g[i][j] = INF;
    66             }
    67         Prim(1);
    68         int ans = 0;
    69         for(int i = 1; i <= n; i++)
    70             ans += vx[i].key;
    71         printf("%d
    ", ans);
    72 
    73     }
    74     return 0;
    75 }

    链接:1789 Truck History

    题目大意:n种卡车,互相之间的差别为同一位置上不同字母的个数,这相当于每个点的权值,根据这个权值来求最小生成树。

    代码,采用邻接矩阵:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <queue>
     4 using namespace std;
     5 
     6 #define maxn 2020
     7 #define INF 10    //预定于的最大值
     8 int n;   //顶点数、边数
     9 int g[maxn][maxn];      //邻接矩阵表示
    10 
    11 struct node     //保存key值的结点
    12 {
    13     int v;
    14     int key;
    15     friend bool operator<(node a, node b)   //自定义优先级,key小的优先
    16     {
    17         return a.key > b.key;
    18     }
    19 };
    20 bool visited[maxn]; //是否已经加入树种
    21 node vx[maxn];      //保存每个结点与其父节点连接边的权值
    22 priority_queue<node> q; //优先队列stl实现
    23 void Prim(int s)    //s表示根结点
    24 {
    25     for(int i = 1; i <= n; i++) //初始化
    26     {
    27         vx[i].v = i;
    28         vx[i].key = INF;
    29         visited[i] = false;
    30     }
    31     vx[s].key = 0;
    32     q.push(vx[s]);
    33     while(!q.empty())
    34     {
    35         node nd = q.top();  //取队首,记得赶紧pop掉
    36         q.pop();
    37         if(visited[nd.v] == true)   //深意,因为push机器的可能是重复但是权值不同的点,我们只取最小的
    38             continue;
    39         int st = nd.v;
    40         visited[nd.v] = true;
    41         for(int j = 1;  j <= n; j++)
    42         {
    43             if(j!=st && !visited[j] && g[st][j] < vx[j].key)    //判断
    44             {
    45                 vx[j].key = g[st][j];
    46                 q.push(vx[j]);
    47             }
    48         }
    49     }
    50 }
    51 char tk[2020][8];
    52 int main()
    53 {
    54     while(scanf("%d", &n), n)
    55     {
    56         for(int i = 1; i <= n; i++)
    57             scanf("%s", tk[i]);
    58         for(int i = 1; i < n; i++)
    59         {
    60             for(int j = i+1; j <= n; j++)
    61             {
    62                 int cnt = 0;
    63                 for(int k = 0; k < 7; k++)
    64                     if(tk[i][k] != tk[j][k])
    65                         cnt++;
    66                 g[i][j] = g[j][i] = cnt;
    67             }
    68         }
    69         Prim(1);
    70         int ans = 0;
    71         for(int i = 1; i <= n; i++)
    72             ans += vx[i].key;
    73         printf("The highest possible quality is 1/%d.
    ", ans);
    74     }
    75     return 0;
    76 }

    链接:2485 Highways

    题目大意:依然是最小生成树,输出权值最大的边。

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <queue>
     4 using namespace std;
     5 
     6 #define maxn 510
     7 #define INF 0xffffff    //预定于的最大值
     8 int n;   //顶点数、边数
     9 int g[maxn][maxn];      //邻接矩阵表示
    10 
    11 struct node     //保存key值的结点
    12 {
    13     int v;
    14     int key;
    15     friend bool operator<(node a, node b)   //自定义优先级,key小的优先
    16     {
    17         return a.key > b.key;
    18     }
    19 };
    20 bool visited[maxn]; //是否已经加入树中
    21 node vx[maxn];      //保存每个结点与其父节点连接边的权值
    22 priority_queue<node> q; //优先队列stl实现
    23 void Prim(int s)    //s表示根结点
    24 {
    25     for(int i = 1; i <= n; i++) //初始化
    26     {
    27         vx[i].v = i;
    28         vx[i].key = INF;
    29         visited[i] = false;
    30     }
    31     vx[s].key = 0;
    32     q.push(vx[s]);
    33     while(!q.empty())
    34     {
    35         node nd = q.top();  //取队首,记得赶紧pop掉
    36         q.pop();
    37         if(visited[nd.v] == true)   //深意,因为push机器的可能是重复但是权值不同的点,我们只取最小的
    38             continue;
    39         int st = nd.v;
    40         visited[nd.v] = true;
    41         for(int j = 1;  j <= n; j++)
    42         {
    43             if(j!=st && !visited[j] && g[st][j] < vx[j].key)    //判断
    44             {
    45                 vx[j].key = g[st][j];
    46                 q.push(vx[j]);
    47             }
    48         }
    49     }
    50 }
    51 int main()
    52 {
    53     int t;
    54     scanf("%d", &t);
    55     while(t--)
    56     {
    57         scanf("%d", &n);
    58         for(int i = 1; i <= n; i++)
    59         {
    60             for(int j = 1; j <= n; j++)
    61                 scanf("%d", &g[i][j]);
    62             g[i][i] = INF;
    63         }
    64         Prim(1);
    65         int ans = 0;
    66         for(int i = 1; i <= n; i++)
    67             if(vx[i].key > ans)
    68                 ans = vx[i].key;
    69         printf("%d
    ", ans);
    70 
    71     }
    72     return 0;
    73 }

    HDOJ

    链接:1863 畅通工程

    题目大意:求全省畅通最低成本,最小生成树,判断能否生成一棵树,如果能输出最小代价,不能输出 ? 

    代码,采用邻接表:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <queue>
      4 using namespace std;
      5 
      6 #define maxn 110  //最大顶点个数
      7 int n, m;       //顶点数,边数
      8 
      9 struct arcnode  //边结点
     10 {
     11     int vertex;     //与表头结点相邻的顶点编号
     12     int weight;     //连接两顶点的边的权值
     13     arcnode * next; //指向下一相邻接点
     14     arcnode() {}
     15     arcnode(int v,int w):vertex(v),weight(w),next(NULL) {}
     16 };
     17 
     18 struct vernode      //顶点结点,为每一条邻接表的表头结点
     19 {
     20     int vex;    //当前定点编号
     21     arcnode * firarc;   //与该顶点相连的第一个顶点组成的边
     22 }Ver[maxn];
     23 
     24 void Init()  //建立图的邻接表需要先初始化,建立顶点结点
     25 {
     26     for(int i = 1; i <= n; i++)
     27     {
     28         Ver[i].vex = i;
     29         Ver[i].firarc = NULL;
     30     }
     31 }
     32 
     33 void Insert(int a, int b, int w)   //头插法,效率更高,但不能去重边
     34 {
     35     arcnode * q = new arcnode(b, w);
     36     if(Ver[a].firarc == NULL)
     37         Ver[a].firarc = q;
     38     else
     39     {
     40         arcnode * p = Ver[a].firarc;
     41         q->next = p;
     42         Ver[a].firarc = q;
     43     }
     44 }
     45 
     46 struct node     //保存key值的结点
     47 {
     48     int v;
     49     int key;
     50     friend bool operator<(node a, node b)   //自定义优先级,key小的优先
     51     {
     52         return a.key > b.key;
     53     }
     54 };
     55 
     56 #define INF 999999999    //权值上限
     57 int parent[maxn];   //每个结点的父节点
     58 bool visited[maxn]; //是否已经加入树种
     59 node vx[maxn];      //保存每个结点与其父节点连接边的权值
     60 priority_queue<node> q; //优先队列stl实现
     61 void Prim(int s)    //s表示根结点
     62 {
     63     for(int i = 1; i <= n; i++) //初始化
     64     {
     65         vx[i].v = i;
     66         vx[i].key = INF;
     67         parent[i] = -1;
     68         visited[i] = false;
     69     }
     70     vx[s].key = 0;
     71     q.push(vx[s]);
     72     while(!q.empty())
     73     {
     74         node nd = q.top();  //取队首,记得赶紧pop掉
     75         q.pop();
     76         if(visited[nd.v] == true)
     77             continue;
     78         visited[nd.v] = true;
     79         arcnode * p = Ver[nd.v].firarc;
     80         while(p != NULL)    //找到所有相邻结点,若未访问,则入队列
     81         {
     82             if(!visited[p->vertex] && p->weight < vx[p->vertex].key)
     83             {
     84                 parent[p->vertex] = nd.v;
     85                 vx[p->vertex].key = p->weight;
     86                 vx[p->vertex].v = p->vertex;
     87                 q.push(vx[p->vertex]);
     88             }
     89             p = p->next;
     90         }
     91     }
     92 }
     93 int main()
     94 {
     95     int a, b, w;
     96     while(scanf("%d%d", &m, &n), m)
     97     {
     98         Init();
     99         while(m--)
    100         {
    101             scanf("%d%d%d", &a, &b, &w);
    102             if(a != b)
    103             {
    104                 Insert(a, b, w);
    105                 Insert(b, a, w);
    106             }
    107         }
    108         Prim(1);
    109         int cnt = 0, ans = 0;
    110         for(int i = 1; i <= n; i++)
    111         {
    112             if(parent[i] == -1)
    113                 cnt++;
    114             ans += vx[i].key;
    115         }
    116         if(cnt >= 2)
    117             printf("?
    ");
    118         else
    119             printf("%d
    ", ans);
    120 
    121     }
    122     return 0;
    123 }

    链接:1875 畅通工程再续

    题目大意:依然是最小生成树,但是点换成了坐标表示,权值表示为两点的距离,求最小权值的和。

    代码,邻接表:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cmath>
      4 #include <queue>
      5 using namespace std;
      6 
      7 #define maxn 110  //最大顶点个数
      8 int n;       //顶点数,边数
      9 
     10 struct arcnode  //边结点
     11 {
     12     int vertex;     //与表头结点相邻的顶点编号
     13     double weight;     //连接两顶点的边的权值
     14     arcnode * next; //指向下一相邻接点
     15     arcnode() {}
     16     arcnode(int v,double w):vertex(v),weight(w),next(NULL) {}
     17 };
     18 
     19 struct vernode      //顶点结点,为每一条邻接表的表头结点
     20 {
     21     int vex;    //当前定点编号
     22     arcnode * firarc;   //与该顶点相连的第一个顶点组成的边
     23 }Ver[maxn];
     24 
     25 void Init()  //建立图的邻接表需要先初始化,建立顶点结点
     26 {
     27     for(int i = 1; i <= n; i++)
     28     {
     29         Ver[i].vex = i;
     30         Ver[i].firarc = NULL;
     31     }
     32 }
     33 
     34 void Insert(int a, int b, double w)  //尾插法,插入以a为起点,b为终点,权为w的边,效率不如头插,但是可以去重边
     35 {
     36     arcnode * q = new arcnode(b, w);
     37     if(Ver[a].firarc == NULL)
     38         Ver[a].firarc = q;
     39     else
     40     {
     41         arcnode * p = Ver[a].firarc;
     42         q->next = p;
     43         Ver[a].firarc = q;
     44     }
     45 }
     46 
     47 struct node     //保存key值的结点
     48 {
     49     int v;
     50     double key;
     51     friend bool operator<(node a, node b)   //自定义优先级,key小的优先
     52     {
     53         return a.key > b.key;
     54     }
     55 };
     56 
     57 #define INF 1e10    //权值上限
     58 #define eps 1e-9
     59 int parent[maxn];   //每个结点的父节点
     60 bool visited[maxn]; //是否已经加入树种
     61 node vx[maxn];      //保存每个结点与其父节点连接边的权值
     62 priority_queue<node> q; //优先队列stl实现
     63 void Prim(int s)    //s表示根结点
     64 {
     65     for(int i = 1; i <= n; i++) //初始化
     66     {
     67         vx[i].v = i;
     68         vx[i].key = INF;
     69         parent[i] = -1;
     70         visited[i] = false;
     71     }
     72     vx[s].key = 0;
     73     q.push(vx[s]);
     74     while(!q.empty())
     75     {
     76         node nd = q.top();  //取队首,记得赶紧pop掉
     77         q.pop();
     78         if(visited[nd.v] == true)
     79             continue;
     80         visited[nd.v] = true;
     81         arcnode * p = Ver[nd.v].firarc;
     82         while(p != NULL)    //找到所有相邻结点,若未访问,则入队列
     83         {
     84             if(!visited[p->vertex] && p->weight < vx[p->vertex].key)
     85             {
     86                 parent[p->vertex] = nd.v;
     87                 vx[p->vertex].key = p->weight;
     88                 vx[p->vertex].v = p->vertex;
     89                 q.push(vx[p->vertex]);
     90             }
     91             p = p->next;
     92         }
     93     }
     94 }
     95 void Show()     //打印图的邻接表(有权值)
     96 {
     97     for(int i = 1; i <= n; i++)
     98     {
     99         cout << Ver[i].vex;
    100         arcnode * p = Ver[i].firarc;
    101         while(p != NULL)
    102         {
    103             cout << "->(" << p->vertex << "," << p->weight << ")";
    104             p = p->next;
    105         }
    106         cout << "->NULL" << endl;
    107     }
    108 }
    109 struct Point
    110 {
    111     int x, y;
    112 }PT[maxn];
    113 double dis(Point p1, Point p2)
    114 {
    115     return 100.0*sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
    116 }
    117 int main()
    118 {
    119     int t;
    120     scanf("%d", &t);
    121     while(t--)
    122     {
    123         scanf("%d", &n);
    124         for(int i = 1; i <= n; i++)
    125             scanf("%d%d", &PT[i].x, &PT[i].y);
    126         Init();
    127         for(int i = 1; i < n; i++)
    128             for(int j = i+1; j <= n; j++)
    129             {
    130                 double d = dis(PT[i], PT[j]);
    131                 if(1000.00 - d > eps || d -100000.00 > eps)
    132                     continue;
    133                 Insert(i, j, d);
    134                 Insert(j, i, d);
    135             }
    136         Prim(1);
    137         int cnt = 0;
    138         double ans = 0;
    139         for(int i = 1; i <= n; i++)
    140         {
    141             if(parent[i] == -1)
    142                 cnt++;
    143             ans += vx[i].key;
    144             if(cnt == 2)
    145                 break;
    146         }
    147         if(cnt == 2)
    148             printf("oh!
    ");
    149         else
    150             printf("%.1lf
    ", ans);
    151     }
    152     return 0;
    153 }

    链接:1879

    题目大意:这道题问题在于其中有些边已经存在,即有些路已经被修建好了,我们只需要将已经建好的边的权值置为0就必定会加入到最小生成树中

    问题:这道题用Prim暂时还没过,应该是有什么坑数据,还在钻研

    下面贴Kruskal的代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 #define maxn 110
     7 struct eage
     8 {
     9     int u, v, w;
    10 }EG[5050];
    11 int parent[maxn];
    12 int n, m;
    13 bool cmp(eage a, eage b)
    14 {
    15     return a.w < b.w;
    16 }
    17 int Find(int x)
    18 {
    19     if(parent[x] == -1) return x;
    20     return Find(parent[x]);
    21 }
    22 void Kruskal()
    23 {
    24     for(int i = 1; i <= n; i++)
    25         parent[i] = -1;
    26     sort(EG+1, EG+m+1, cmp);
    27     int ans = 0;
    28     for(int i = 1; i <= m; i++)
    29     {
    30         int x = Find(EG[i].u);
    31         int y = Find(EG[i].v);
    32         if(x != y)
    33         {
    34             ans += EG[i].w;
    35             parent[x] = y;
    36         }
    37     }
    38     printf("%d
    ", ans);
    39 }
    40 int main()
    41 {
    42     int w, f;
    43     while(scanf("%d", &n), n)
    44     {
    45         m = n*(n-1)/2;
    46         for(int i = 1; i <= m; i++)
    47         {
    48             scanf("%d%d%d%d", &EG[i].u, &EG[i].v, &w, &f);
    49             if(f == 1)
    50                 w = 0;
    51             EG[i].w = w;
    52         }
    53         Kruskal();
    54     }
    55     return 0;
    56 }
  • 相关阅读:
    [java] 深入理解内部类: inner-classes
    [java] 更好的书写equals方法-汇率换算器的实现(4)
    [java] 注释以及javadoc使用简介-汇率换算器的实现-插曲3
    [java] jsoup使用简介-汇率换算器实现-插曲2
    [java] 汇率换算器实现(3)
    [java] 汇率换算器实现-插曲1-正则表达式(1)
    [java] 汇率换算器实现(2)
    [java] 汇率换算器实现(1)
    [Basic] The most basic things about java
    电路相关知识–读<<继电器是如何成为CPU的>>
  • 原文地址:https://www.cnblogs.com/dzkang2011/p/gen_tree.html
Copyright © 2011-2022 走看看