hdu 1863 畅通工程(prim算法实现和kruskal算法实现)

最小生成树的prim算法,思想就是先指定一个点进入点集A(A为已处理过的点的集合),以改点为起点,扫描和该点连接的路径,取最小值计入总路径长度sum,并把该路径的另一点并入A,再以这点为起点扫描……最后得到的sum即为结果

prim的邻接阵代码:

#include <stdio.h>  
#include <string.h>  
#define size 105  
#define INIT 999999  
  
int count;  
int Graph[size][size];  
long sum;  
  
void Prim(int villige)  
{  
    int i,j;  
    int min,locate;
    int dist[size];  
    sum=0;  
    bool visited[size];  
    memset(visited,0,sizeof(visited));  
    memset(dist,INIT,sizeof(dist));  
    for(i=1;i<=villige;i++)  //默认第一个点已经进入集合
        dist[i] = Graph[1][i]; 
    count = 1;  
    for (j=2;j<=villige;j++)  
    {  
        min = INIT;
		//找到距离已标记集合最近的点
        for(i=2;i<=villige;i++)  
        {  
            if (!visited[i]&&dist[i]<min)  //存在未标记的点,min的值才会改变 
            {  
                min = dist[i];  
                locate = i;  
            }  
        } 
		
        if(min!=INIT) //如果min值改变
        {  
            visited[locate] = true;  
            sum+=min;  
            count++;
			//dist[]的更新
            for (i=1;i<=villige;i++)  
            {//已经标记过的点,还有自身不用考虑,然后把集合外的点到集合的最小距离存入dist[]
                if(!visited[i]&&Graph[locate][i]!=0&&dist[i]>Graph[locate][i])  
                    dist[i] = Graph[locate][i];  
            }  
        }  
        else return ;  
    }  
}  
int main()  
{  
    int road,villige;  
    int i,j,weight;  
    while (scanf("%d%d",&road,&villige)!=EOF&&road)  
    {  
        count = 0;  
        for(i=0;i<=villige;i++)  
        {  
            for(j=0;j<=villige;j++)  
                if(i==j)  
                    Graph[i][j] = 0;  
                else  
                    Graph[i][j] = INIT;  
        }  
        while (road--)  
        {  
            scanf("%d%d%d",&i,&j,&weight);  
            Graph[i][j] = weight;  
            Graph[j][i] = weight;  
        }  
        Prim(villige);  
        if(count==villige) printf("%ld/n",sum);  
        else printf("?/n");        
    }  
    return 0;  
}
prim的邻接表代码:

#include<cstdio>
#include<cstring>
#include<climits>
const int N = 205;

struct Edge{
	int s,e,v;
	int next;
}edge[N];

int e_num,n,m,head[N],vis[N],dist[N];

void AddEdge(int a,int b,int c){
	edge[e_num].s=a; edge[e_num].e=b; edge[e_num].v=c;
	edge[e_num].next=head[a]; head[a]=e_num++;

	edge[e_num].s=b; edge[e_num].e=a; edge[e_num].v=c;
	edge[e_num].next=head[b]; head[b]=e_num++;
}

void getmap(){
	int a,b,c;
	e_num=0;
	memset(head,-1,sizeof(head));
	memset(vis,0,sizeof(vis));

	while(m--){
		scanf("%d%d%d",&a,&b,&c);
		AddEdge(a,b,c);
	}
}

void prim(){
	int i,j,cur;
	for(i=1;i<=n;dist[i++]=INT_MAX);
	for(i=head[1];i!=-1;i=edge[i].next)
		dist[edge[i].e]=(edge[i].v<dist[edge[i].e]?edge[i].v:dist[edge[i].e]);
	vis[1]=1;

	int sum=0;
	int count=1;
	for(i=2;i<=n;i++){
		int min=INT_MAX;
		for(j=1;j<=n;j++){
			if(!vis[j] && dist[j]<min){
				min=dist[j]; cur=j;
			}
		}
		if(min==INT_MAX)break;
		sum+=min;
		vis[cur]=1;
		count++;

		if(count==n)break;

		for(j=head[cur];j!=-1;j=edge[j].next){
			int u=edge[j].e;
			if(!vis[u] && dist[u]>edge[j].v)
				dist[u]=edge[j].v;
		}
	}
	count<n?printf("?\n"):printf("%d\n",sum);
}

int main()
{
	while(scanf("%d%d",&m,&n),m)//m条路径,n个点
	{
		getmap();
		prim();
	}
	return 0;
}
kruskal算法就是并查集思想。把所有路径按权值排升序,依次取不使当前图产生回路的边,直到所有点并入集合
代码:
# include<stdio.h>
# include<string.h>
#include<stdlib.h>
int father[101];
struct node
{
	int from,to;
	int len;
}path[5001];
int cmp(const void *a,const void *b)
{
	struct node *aa=(struct node *)a;
	struct node *bb=(struct node *)b;
	return aa->len - bb->len;
}
int findfather(int x)
{
	if(father[x]!=x)
		father[x]=findfather(father[x]);
	return father[x];
}
void init()
{
	int i;
	for(i=1;i<=100;i++)
		father[i]=i;
}
void merge(int a,int b)
{
	int x,y;
	x=findfather(a);
	y=findfather(b);
	if(x!=y)father[y]=x;
}
int main()
{
	int i,n,m,s,cnt;
	while(scanf("%d%d",&n,&m),n)
	{
		init();
		for(i=0;i<n;i++)
			scanf("%d%d%d",&path[i].from,&path[i].to,&path[i].len);
		
		qsort(path,n,sizeof(path[0]),cmp);
		for(s=0,i=0;i<n;i++)
		{
			if( findfather(path[i].from) != findfather(path[i].to) )
			{
				merge(path[i].from,path[i].to);
				s+=path[i].len;
			}
		}	
		for(i=1;i<=m;i++)
			father[i]=findfather(i);
		for(cnt=0,i=1;i<=m;i++)
		{
			
			if(father[i]==i)
				cnt++;
		}
		if(cnt>1) printf("?\n");
		else printf("%d\n",s);
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值