• 题解报告:hdu 1863 畅通工程


    Problem Description
    省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。
    Input
    测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N 行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
    Output
    对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
    Sample Input
    3 3
    1 2 1
    1 3 2
    2 3 4
    1 3
    2 3 2
    0 100
    Sample Output
    3
    ?
    解题思路:全省畅通也就是求最小生成树,如果给出的数据不全,得到的将是INF,此时输出'?',否则输出对应的最小代价。
    AC代码之Prim算法:
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int INF = 0x3f3f3f3f;
     4 int m,n,a,b,c,mincost[105],cost[105][105];
     5 bool vis[105];
     6 void Prim(){
     7     for(int i=1;i<=n;++i)
     8         mincost[i]=cost[1][i];
     9     mincost[1]=0;vis[1]=true;
    10     int res=0;
    11     for(int i=1;i<n;++i){//m-1个节点
    12         int k=-1;
    13         for(int j=1;j<=n;++j)//这里更新一下获得的新发现,循环到第二次时会默认地把mincost[2]当作最小值,然后与剩下的元素比较,找到最小
    14             if(!vis[j] && (k==-1||mincost[k]>mincost[j]))k=j;
    15         if(k==-1)break;
    16         if(mincost[k]==INF)break;//如果此时的最小值还是INF,说明统计数据不足,直接退出
    17         vis[k]=true;
    18         res+=mincost[k];
    19         for(int j=1;j<=n;++j)
    20             if(!vis[j])mincost[j]=min(mincost[j],cost[k][j]);
    21     }
    22     bool flag=false;//标记是否还有未访问
    23     for(int i=1;i<=n;++i)
    24         if(!vis[i]){flag=true;break;}//如果还有未被访问,说明统计数据不全,输出'?'
    25     if(flag)cout<<'?'<<endl;
    26     else cout<<res<<endl;
    27 }
    28 int main()
    29 {
    30     while(cin>>m>>n && m){
    31         memset(vis,false,sizeof(vis));
    32         for(int i=1;i<=n;++i)
    33             for(int j=1;j<=n;++j)
    34                 cost[i][j]=(i==j?0:INF);
    35         for(int i=1;i<=m;++i){
    36             cin>>a>>b>>c;
    37             cost[a][b]=cost[b][a]=c;
    38         }
    39         Prim();
    40     }
    41     return 0;
    42 }

     AC之Kruskal算法(并查集):判断数据不全的依据是如果所有节点的根节点不一样,即不在同一个集合时输出'?',否则输出最小代价即可。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int m,n,father[105],sum;
     4 struct edge{int u,v,cost;}es[5000];//可能有n*(n-1)/2条边,因为这是无向有权图,此时开5000长度已经够了
     5 bool cmp(const edge& e1,const edge& e2){//引用,减少拷贝所花时间
     6     return e1.cost<e2.cost;
     7 }
     8 void init_union_find(){//将每个节点当作根节点
     9     for(int i=1;i<=n;++i)father[i]=i;
    10 }
    11 int find_father(int x){//递归查找根节点
    12     if(father[x]==x)return x;
    13     else return father[x]=find_father(father[x]);
    14 }
    15 void unite(int x,int y,int z){
    16     x=find_father(x);
    17     y=find_father(y);
    18     if(x!=y){//如果边的两端点的根节点不相同,即分别为非连通图,则可以归并
    19         sum+=z;//加上最小权值
    20         father[x]=y;
    21     }
    22 }
    23 int main()
    24 {
    25     while(cin>>m>>n && m){
    26         for(int i=1;i<=m;++i)
    27             scanf("%d %d %d",&es[i].u,&es[i].v,&es[i].cost);
    28         sort(es+1,es+m+1,cmp);//权值按从小到大排序
    29         sum=0;init_union_find();//初始化
    30         for(int i=1;i<=m;++i)
    31             unite(es[i].u,es[i].v,es[i].cost);
    32         bool flag=false;
    33         for(int i=2;i<=n;++i)//判断是否在同一个集合中
    34             if(find_father(1)!=find_father(i)){flag=true;break;}
    35         if(flag)cout<<'?'<<endl;
    36         else printf("%d
    ",sum);
    37     }
    38     return 0;
    39 }
  • 相关阅读:
    Linux kill, killall, kill -9
    mongodb分片集群(无副本集)搭建
    如何用vs查看结构体布局
    Winsock在Windows下的编程教程(C语言)(图文并茂,超长教程)
    HTTPS 中双向认证SSL 协议的具体过程
    RAR压缩解压命令
    x64栈结构
    ASP.NET Web API下的HttpController激活:程序集的解析
    Lucene学习-深入Lucene分词器,TokenStream获取分词详细信息
    IO多路复用之select
  • 原文地址:https://www.cnblogs.com/acgoto/p/9054617.html
Copyright © 2020-2023  润新知