POJ 1251 (2013.9.21周赛H题:MST最小生成树prim和kruskal算法)

题意: Lagrishan的一个热带岛屿上的行政长官有一个问题要解决。他决定把几年前得到的外国援助资金用于修建村庄之间的道路。但是丛林比道路多太多了,使道路网络的维护太过于昂贵了。理事会必须选择停止维修一些道路。上述左侧图显示当前所有使用中的道路,以及现在每月的维护费用。当然,村庄之间必需有一些公路能够相通,即使路线并不像以前一样短。行政长官想告诉理事会怎样才使每月的花费最小,并且所维持的道路,将连接所有村庄。上面的地图标记了村庄A到I。右边的图显示了每月能够维护道路的最小费用为216aacms。你的任务是编写一个程序,将解决这些问题。
输入:

输入包含的数据集个数在100以内,以0作为最后一行。每个数据集的第一行只包含一个表示村庄个数的数n,1<n<27,并且这n个村庄是由大写字母表里的前n个字母表示。接下来的n- 1行是由字母表的前n-1个字母开头。最后一个村庄表示的字母不用输入。对于每一行,以每个村庄表示的字母开头,然后后面跟着一个数字,表示有多少条道路可以从这个村到后面字母表中的村庄。如果k是大于0,表示该行后面会表示k条道路的k个数据。每条道路的数据是由表示连接到另一端村庄的字母和每月维修该道路的花费组成。维修费用是正整数的并且小于100。该行的所有数据字段分隔单一空白。该公路网将始终连接所有的村庄。该公路网将永远不会超过75条道路。没有任何一个村庄会有超过15条的道路连接到其他村庄(之前或之后的字母)。在下面的示例输入,其中第一个数据集是与上面的地图相一致的。

思路:最小生成树,以前还没做过,而且那时学长教的PPT没仔细看,只是大概看了一下,然后现在重新开始看,对prim算法了解了一点,对kruskal算法还不明白多少,努力中,这个代码还是参考别人的,正在学习最小生成树中……

prim算法代码如下:

#include<iostream>
using namespace std;
int n,a;
int map[27][27],d[27];
int min(int a,int b)
{
    return a<b?a:b;
}
void prim()
{
    int i,j,now,min1,min2;
    now=1;
    a=0;
    for(i=1;i<n;i++)
    {
        d[now]=-1;
        min1=100000000;
        for(j=1;j<=n;j++)
            if(now!=j&&d[j]>=0)
            {
                d[j]=min(d[j],map[now][j]);
                if(d[j]<min1)
                {
                    min1=d[j];
                    min2=j;
                }
            }
            now=min2;
            a+= min1;
    }
    cout<<a<<endl;
}
int main()
{
    int i,j,num,m;
    char u,v;
    while(cin>>n&&n)
    {
        for(i=1;i<=n;i++)
        {
            d[i]=100000000;
            for(j=1;j<=n;j++)
                map[i][j]=100000000;
        }
        for(i=1;i<n;i++)
        {
            cin>>u>>num;
            while(num--)
            {
                cin>>v>>m;
                map[u-'A'+1][v-'A'+1]=m;
                map[v-'A'+1][u-'A'+1]=m;
            }
        }
        prim();
    }
    return 0;
}

kruskal算法代码如下:

#include<iostream>
#include <algorithm>
using namespace std;
typedef struct  //定义边(x,y),权即边长为w
{
	int x,y;
	int w;
}a;
a e[27*27];
int rank[27],father[27],sum;  //rank[x]表示x的秩
bool cmp(a p,a q)
{
     return p.w<q.w;
}
int find(int x) //查找x元素所在的集合,回溯时压缩路径
{
    return father[x]==x?x:find(father[x]);
}
void un(int x,int y,int w) //合并x,y所在的集合,krustal算法因为即使边是最小的,若产生回路则不取,所以要合并集合,看看产不产生回路
{
	if(x==y) return;
	if(rank[x]>rank[y]) father[y]=x;     //这其实是并查集的算法,因为回路问题,所以有了krustal算法,可以说是并查集的完美应用!
	else
	{
		if(rank[x]==rank[y]) rank[y]++;
		father[x]=y;
	}
	sum+=w;
}
int main()
{
	int i,j,k,m,n,t;
	char c;
	while(cin>>m&&m)
	{
		for(i=0;i<m;i++)
		{
		    father[i]=i;
            rank[i]=0;
		}
		for(i=0,k=0;i<m-1;i++)
		{
			cin>>c>>n;
			for(j=0;j<n;j++)
			{
				cin>>c>>e[k].w;
				e[k].x=i;
				e[k].y=c-'A';
				k++;
			}
		}
		sort(e,e+k,cmp);
		sum=0;
		for(i=0;i<k;i++) un(find(e[i].x),find(e[i].y),e[i].w);
		cout<<sum<<endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值