hdu1863 畅通工程 Kruskal 和 Prime求最小生成树

来源:互联网 发布:linux vi怎么保存 编辑:程序博客网 时间:2024/05/18 03:54

畅通工程

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 26667    Accepted Submission(s): 11655


Problem Description
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。
 

Input
测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N 
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
 

Output
对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
 

Sample Input
3 31 2 11 3 22 3 41 32 3 20 100
 

Sample Output
3?
 

Source
浙大计算机研究生复试上机考试-2007年

两个算法都用来求最小生成树。。。

zyyyyy之前在天黑板(滑稽)上讲过Kruskal算法,即对所有的边根据花费来排个序,然后利用并查集每次贪心地选最小的边加入当前的最小生成树。

Kruskal版本:

#include <iostream>#include <string>#include <cstdio>#include <algorithm>#include <vector>#include <queue>#include <cmath>using namespace std;const int maxn = 110;int n,m;int father[maxn];struct unit {    int from,to;    long long cost;}save[maxn*maxn];bool compare(unit a,unit b){    return a.cost<b.cost;}int find(int x){    if(x==father[x]) return x;    return father[x] = find(father[x]);}bool isConnected(int a,int b){    return find(a) == find(b);}void mix(int a,int b){    int u = find(a),v = find(b);    if(u==v){        return ;    }    father[u] = v;}long long Kruskal(){    long long result = 0;    sort(save+1, save+1+m, compare);    for(int i =1 ;i<=m;i++){        if(isConnected(save[i].from, save[i].to)){            continue;        }        mix(save[i].from, save[i].to);        result += save[i].cost;    }    return result;}int main(){    while(scanf("%d%d",&m,&n)&&m){        int i;        for(i=1;i<=n;i++){            father[i]=i;        }        for(i=1;i<=m;i++){            scanf("%d%d%lld",&save[i].from,&save[i].to,&save[i].cost);        }        bool flag = true;        long long result = Kruskal();        for(i=1;i<=n;i++){            if(!isConnected(1, i)){                flag = false;            }        }        if(flag){            printf("%lld\n",result);        }else{            printf("?\n");        }    }    return 0;}

而Prime算法好像更复杂一点?想法和Kruskal差不多

利用优先队列来储存每个点连接的边,程序一开始,随机地选择一个点作为起点,每次都是选择和这条边相连并且没有访问过的点的最短的边加入最小生成树,然后标记这些访问过的点。

Prime版本:

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <vector>#include <queue>#include <cmath>using namespace std;const int maxn = 110;int n,m;int father[maxn];struct unit {    int from,to;    long long cost;    bool operator < (const unit &a)const{        return a.cost<cost;    }};priority_queue<unit> que;vector<unit> cost[maxn];bool vis[maxn];//is visited?long long  Prime(){    long long result = 0;    vis[1] =true;    int i;    for(i=0;i<cost[1].size();i++){        que.push(cost[1][i]);    }    while(que.size()){        unit now = que.top();        que.pop();        if(!vis[now.to]){            result += now.cost;            vis[now.to] = true;            for(i=0;i<cost[now.to].size();i++){                que.push(cost[now.to][i]);            }        }    }    return result;}int main(){    while(scanf("%d%d",&m,&n)&&m){        int i;        for(i=1;i<=n;i++){            cost[i].clear();        }        memset(vis, false, sizeof(vis));        while(que.size()){            que.pop();        }        for(i=1;i<=m;i++){            unit now;            scanf("%d%d%lld",&now.from,&now.to,&now.cost);            cost[now.from].push_back(now);        }        bool flag = true;        long long result = Prime();        for(i=1;i<=n;i++){            if(!vis[i]){                flag = false;            }        }        if(flag){            printf("%lld\n",result);        }else{            printf("?\n");        }    }    return 0;}





0 0
原创粉丝点击