hdu1879 最小生成树模板 peim和kruskal

来源:互联网 发布:菲律宾网络诈骗 编辑:程序博客网 时间:2024/06/11 04:04

 Problem Description
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。
 

Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。

当N为0时输入结束。
 

Output
每个测试用例的输出占一行,输出全省畅通需要的最低成本。

思路,典型的最小生成数。鉴于网上有一些贴出来的模板可能有一些错误什么的,所以在这里我就贴出实现最小生成树的两种算法,peim和kruskal。

#include <stdio.h>#include <string.h>const int N=105;const int inf=10000000;int map[N][N],n;int vis[N*(N+1)/2];int dis[N*(N+1)/2];void Prime(){    memset(vis,0,sizeof(vis));    for(int i = 1 ; i <= n ; i++)    {        if(i==1)map[1][i]=inf;        else dis[i]=map[1][i];    }    int loc,sum=0;    for(int i = 1 ; i <= n ; i++)    {       int min=inf;       for(int j = 1 ; j <= n ; j++)       {           if(!vis[j]&&dis[j]<min)           {               min=dis[j];               loc=j;           }       }       vis[loc]=1;       sum+=min;       for(int j = 1 ; j <= n ; j++)       {           if(!vis[j]&&map[loc][j]<dis[j])           {               dis[j]=map[loc][j];           }       }    }    printf("%d\n",sum);}int main(){    while(scanf("%d",&n),n)    {        for(int i=1;i<=n;i++)        {            for(int j=1;j<=n;j++)            {                map[i][j]=inf;            }        }        int m = n*(n-1)/2;        int a,b,c,d;        for(int i = 1 ; i <= m ; i++)        {            scanf("%d%d%d%d",&a,&b,&c,&d);            if(d==1)map[a][b]=map[b][a]=0;            else map[a][b]=map[b][a]=c;        }        Prime();    }    return 0;}



/*典型的最小生成树,在做并查集时做的这道题,所以使用并查集实现的克鲁斯卡尔算法*/#include <iostream>#include <stdio.h>#include <algorithm>using namespace std;struct node {    int start ,end,expense,flag;}data[5005];int father[105];void make_set(int n){    for(int i=1;i<=n;i++)        father[i]=i;}int find_set(int x){    if(x^father[x])        father[x]=find_set(father[x]);    return father[x];}int union_set(int x,int y){    x=find_set(x);    y=find_set(y);    if(x==y)        return 0;    father[x]=y;    return 1;}bool cmp(node a,node b){    return a.expense<b.expense;}int main(){    int n;    while(scanf("%d",&n)!=EOF)    {        if(!n)            break;        make_set(n);        int ans=0;        int m=(n-1)*n/2;        for(int i=0;i<m;i++)        {            scanf("%d%d%d%d",&data[i].start,&data[i].end,&data[i].expense,&data[i].flag);            if(data[i].flag)//当道路修通时,规定一节点为另一节点的父亲                father[data[i].start]=data[i].end;        }        sort(data,data+m,cmp);//按道路的花费升序排列        //在不构成环的前提下,选择最短的边,有贪心的思想        for(int i=0;i<m;i++)        {            if(union_set(data[i].start,data[i].end))                ans+=data[i].expense;        }        printf("%d\n",ans);    }    return 0;}


最后再贴出一个实现最大生成树的代码,其他意思都没有变,就是要求权值最大的生成树。

#include <stdio.h>#include <string.h>const int N=105;const int inf=10000000;int map[N][N],n;int vis[N*(N+1)/2];int dis[N*(N+1)/2];void Prime(){    memset(vis,0,sizeof(vis));    for(int i = 2 ; i <= n ; i++)    {       dis[i]=map[1][i];    }    int loc,sum=0;    for(int i = 2 ; i <= n ; i++)    {       int min=0;       for(int j = 1 ; j <= n ; j++)       {           if(!vis[j]&&dis[j]>min)           {               min=dis[j];               loc=j;           }       }       vis[loc]=1;       sum+=min;       for(int j = 2 ; j <= n ; j++)       {           if(!vis[j]&&map[loc][j]>dis[j])           {               dis[j]=map[loc][j];           }       }    }    printf("%d\n",sum);}int main(){    while(scanf("%d",&n)!=EOF)    {        for(int i=1;i<=n;i++)        {            for(int j=1;j<=n;j++)            {                scanf("%d",&map[i][j]);            }        }        Prime();    }    return 0;}



0 0
原创粉丝点击