• ACM Contest and Blackout UVA


      In order to prepare the “The First National ACM School Contest” (in 20??) the major of the city decided to provide all the schools with a reliable source of power. (The major is really afraid of blackoutsJ). So, in order to do that, power station “Future” and one school (doesn’t matter which one) must be connected; in addition, some schools must be connected as well.

       You may assume that a school has a reliable source of power if it’s connected directly to “Future”, or to any other school that has a reliable source of power. You are given the cost of connection between some schools. The major has decided to pick out two the cheapest connection plans – the cost of the connection is equal to the sum of the connections between the schools. Your task is to help the major — find the cost of the two cheapest connection plans.

    Input

       The Input starts with the number of test cases, T (1 < T < 15) on a line. Then T test cases follow. The first line of every test case contains two numbers, which are separated by a space, N (3 < N < 100) the number of schools in the city, and M the number of possible connections among them. Next M lines contain three numbers Ai , Bi , Ci , where Ci is the cost of the connection (1 < Ci < 300) between schools Ai and Bi . The schools are numbered with integers in the range 1 to N.

    Output

      For every test case print only one line of output. This line should contain two numbers separated by a single space – the cost of two the cheapest connection plans. Let S1 be the cheapest cost and S2 the next cheapest cost. It’s important, that S1 = S2 if and only if there are two cheapest plans, otherwise S1 < S2. You can assume that it is always possible to find the costs S1 and S2.

    Sample Input

    2

    5 8

    1 3 75

    3 4 51

    2 4 19

    3 2 95

    2 5 42

    5 4 31

    1 2 9

    3 5 66

    9 14

    1 2 4

    1 8 8

    2 8 11

    3 2 8

    8 9 7

    8 7 1

    7 9 6

    9 3 2

    3 4 7

    3 6 4

    7 6 2

    4 6 14

    4 5 9

    5 6 10

    Sample Output

    110 121

    37 37

    题意:有n个学校要通过电线相互连接,给你每个学校之间的电线图,请你给出两套花费最少的连接方案,让第一个是最便宜的成本,第二个是较便宜的成本

    思路:保证连接的最小花费,很明显就是最小生成树,题意要的是两个成本,那么另一个应该是次小生成树了,代码没什么难的,直接套模板就行。

    代码:

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <algorithm>
      4 #include <cmath>
      5 #include <deque>
      6 #include <vector>
      7 #include <queue>
      8 #include <string>
      9 #include <cstring>
     10 #include <map>
     11 #include <stack>
     12 #include <set>
     13 #include <sstream>
     14 #include <iostream>
     15 #define mod 998244353
     16 #define eps 1e-6
     17 #define ll long long
     18 #define INF 0x3f3f3f3f
     19 using namespace std;
     20 
     21 //ma存放两点之间的初始距离
     22 int ma[105][105];
     23 //low存放到起点的最小距离,
     24 int low[105];
     25 //per存放与当前点连接距离最短的另一个点
     26 int per[105];
     27 //bj用于判断该点时候在生成树中,con用于标记在生成树中的边
     28 bool bj[105],con[105][105];
     29 //maxn存放两点之间的最大值
     30 int maxn[105][105];
     31 int n;
     32 //最小生成树算法,u表示树的起点
     33 int prim(int u)
     34 {
     35     for(int i=1;i<=n;i++)
     36     {  //初始low的距离与per指向的点
     37         low[i]=ma[u][i];
     38         per[i]=u;
     39     }
     40     //初始化标记
     41     memset(maxn,0,sizeof(maxn));
     42     memset(bj,0,sizeof(bj));
     43     memset(con,0,sizeof(con));
     44     //起点是树上的第一个点,标记
     45     bj[u]=1;
     46     //ans保存树的所有权值和
     47     int ans=0;
     48     //遍历其他n-个点
     49     for(int i=1;i<n;i++)
     50     {
     51          //通过遍历找到距离当前起点的最短的边
     52         int mi=INF;
     53         int v=-1;
     54         for(int j=1;j<=n;j++)
     55         {
     56             if(!bj[j]&&low[j]<mi)
     57             {
     58                 mi=low[j];
     59                 v=j;
     60             }
     61         }
     62         //有最短边后
     63         if(v!=-1)
     64         {
     65             //将这个边的两个点标记
     66             con[v][per[v]]=con[per[v]][v]=1;
     67             //累加权值
     68             ans+=mi;
     69             //标记这个点
     70             bj[v]=1;
     71             //记录这个边的值,
     72             maxn[v][per[v]]=maxn[per[v]][v]=mi;
     73              //再遍历一遍,以更新数据
     74             for(int j=1;j<=n;j++)
     75             {
     76                  //j表示的点再树上,且j不是终点
     77                 if(bj[j]&&j!=v)
     78                 {    //更新v与其他在树上的点之间的最大权值
     79                     maxn[j][v]=maxn[v][j]=max(maxn[j][per[v]],maxn[per[v]][v]);
     80                 }
     81                 //j表示的点不在树上,且满足更新需要
     82                 if(!bj[j]&&low[j]>ma[v][j])
     83                 {
     84                     //更新low的距离和per指向的点
     85                     low[j]=ma[v][j];
     86                     per[j]=v;
     87                 }
     88             }
     89         }
     90     }
     91     return ans;
     92 }
     93 
     94 //次小生成树算法,s表示最小生成树的权值和
     95 int secondprim(int s)
     96 {
     97     int ans=INF;
     98     //遍历所有点与其他点
     99     //求最小生成树在外加一条边并且删除环的最大边后的值的最小值
    100     for(int i=1;i<n;i++)
    101     {
    102         for(int j=i+1;j<=n;j++)
    103         {
    104             //如果这个边不在树上
    105             if(!con[i][j])
    106             {   //s+ma-maxn表示最小生成树在加上一条外边
    107                 //并删除外边所在环差外边外的最大值。就是子生成树的权值和
    108                 ans = min(ans,s+ma[i][j]-maxn[i][j]);
    109             }
    110         }
    111     }
    112     return ans;
    113 }
    114 //初始化地图以保证数据的准确性
    115 void build(int s)
    116 {
    117     for(int i=0;i<=s;i++)
    118     {
    119         for(int j=0;j<=s;j++)
    120         {
    121             if(i!=j)
    122             {
    123                 ma[i][j]=INF;
    124             }
    125             else
    126             {
    127                 ma[i][j]=0;
    128             }
    129         }
    130     }
    131 }
    132 int main()
    133 {
    134     int t;
    135     scanf("%d",&t);
    136     while(t--)
    137     {
    138         int m;
    139         scanf("%d %d",&n,&m);
    140         build(n);
    141         int a,b,c;
    142         for(int i=0;i<m;i++)
    143         {
    144             scanf("%d %d %d",&a,&b,&c);
    145             ma[a][b]=ma[b][a]=c;
    146         }
    147         int s1=prim(1);
    148         int s2=secondprim(s1);
    149         printf("%d %d
    ",s1,s2);
    150     }
    151 }
  • 相关阅读:
    基于NFS的PV动态供给(StorageClass)
    Helm学习笔记
    k8s日志收集方案
    okhttputils【 Android 一个改善的okHttp封装库】使用(三)
    PopupWindowMenuUtil【popupwindow样式菜单项列表】
    NewBuiltBottomSheetDialog【新建底部对话框】
    NormalDialogFragmentDemo【普通页面的DialogFragment】
    ArticleRemoveDelDialog【基于AlertDialog的回收删除对话框】
    ConfirmCancelBottomSheetDialog【确认取消底部对话框】
    Android-PickerView【仿iOS的PickerView控件,并封装了时间选择和选项选择这两种选择器】使用
  • 原文地址:https://www.cnblogs.com/mzchuan/p/11837267.html
Copyright © 2020-2023  润新知