记录一次prim算法误用(理解不到位)

题目:

 

样例

7 10
60 10 35 55 40 70 70
0 1 20
0 4 75
0 3 45
1 3 50
1 2 15
2 6 5
5 6 45
4 5 5
3 5 25
3 6 65

输出:120

题解:引入虚拟顶点,与各点连线,权值为安网线费用,求最小生成树。

第一次采用邻接表+prim算法

#include<stdio.h>
#include<stdlib.h>
//#include<time.h>
#define vmax 605
#define emax 200005
#define max 0x7ffff
//邻接表建立
//边表 
typedef struct edgnode
{
	int adjvex;
	int weigh;
	struct edgnode * next;
 }enode;
//顶点表
typedef struct vexnode
{
	int vertex;
    enode * then;
 }vnode;
vnode vlist[vmax];
//建立表
void creat_graph(int numvex,int numedg) 
{
	for(int i = 0;i <= numvex;i++)
	{
		vlist[i].vertex = i+1;
		vlist[i].then = NULL;
	}
	for(int i = 1;i <= numvex;i++)
	{
		enode *s = (enode*)malloc(sizeof(enode));
		enode *m = (enode*)malloc(sizeof(enode));
		s->adjvex = i;
		s->next = NULL;
		if (vlist[numvex + 1].then == NULL)
		{
			vlist[numvex + 1].then = s;
			scanf("%d",&s->weigh);
		}
		else
		{
			enode *p = vlist[numvex + 1].then;
			scanf("%d",&s->weigh);
			vlist[numvex + 1].then = s;
			s->next = p;
		}
		m->adjvex = numvex + 1;
		m->weigh = s->weigh;
		m->next = NULL;
		vlist[i].then = m;
	}
	for(int i = 0;i < numedg;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		u++;
		v++;
		enode *f = (enode*)malloc(sizeof(enode));
		enode *g = (enode*)malloc(sizeof(enode));
		f->adjvex = v;
		f->weigh = w;
		g->adjvex = u;
		g->weigh = w;
		enode *p = vlist[u].then;
		enode *a = vlist[v].then;
		if(!p)
		{
			f->next = NULL;
			vlist[u].then = f;
		}
		else
		{
			vlist[u].then = f;
			f->next = p;
		}
		if(!a)
		{
			g->next = NULL;
			vlist[v].then = g;
		}
		else
		{
			vlist[v].then = g;
			g->next = a;
		}
	}
//	for(int i = 1;i <= numvex + 1;i++)
//	{
//		enode *t = vlist[i].then;
//		if(t)
//		{
//			do
//			{
//			    int pm = t->adjvex;
//			    int pw = t->weigh;
//			    enode *q = (enode*)malloc(sizeof(enode));
//			    q->adjvex = i;
//			    q->weigh = pw;
//			    enode *tmp = vlist[pm].then;
//			    q->next = tmp;
//			    vlist[pm].then = q;
//			    t = t->next;
//			}while(t);
//		}
//	}
}
//打印表 
void print_graph(int numvex)
{
	for(int i = 1;i <= numvex + 1;i++)
	{
		enode *p = vlist[i].then;
		while(p)
		{
			printf("%d %d %d\n",i,p->adjvex,p->weigh);
			p = p->next;
		}
	}
}
void prim(int numvex)
{
	int minp,minw = max;
	int sum = 0;
	int shortpath[numvex + 2];
//	int point[numvex + 2];
	int flag[numvex + 2];
	for(int i = 0;i <= numvex + 2;i++)
	{
		shortpath[i] = max;
		flag[i] = 0;
//		point[i] = 0;
	}
	shortpath[1] = 0;
	flag[1] = 1;
	enode *p = vlist[1].then;
		if(p)
		{
			while(p)
		   {
		        int m = p->adjvex;
		 	    shortpath[m] = p->weigh;
		 	    p = p->next;
		   }
		}
	for(int i = 0;i <= numvex + 2;i++)
	{
		point[i] = 1;
	}
	for(int j = 2;j <= numvex + 1;j++)
	{
		minw = max;
	  	for(int i = 2;i <= numvex + 2;i++)
  	    {
	        if(shortpath[i] < minw&&shortpath[i] != 0)
	        {
	     minw = shortpath[i];
	     minp = i;
	      }
	}
	flag[minp] = 1;
	sum += minw;
//	printf("%d %d %d %d\n",point[minp],minp,minw,sum);//test
//	for(int i = 0;i <= numvex + 2;i++)//test
//	{
//		printf("%d ",shortpath[i]);
//	}
//	printf("\n");
//	for(int i = 0;i <= numvex + 2;i++)//test
//	{
//		printf("%d ",point[i]);
//	} 
//	printf("\n");
//	for(int i = 0;i <= numvex + 2;i++)//test
//	{
//		printf("%d ",flag[i]);
//	}
//	printf("\n");
	for(int t = 2;t <= numvex + 2;t++)
	{
		enode *s =vlist[minp].then;
	       	if(s)
	       	{
	       		while(s)
	      	   {
		    	    int n = s->adjvex;
				    if(s->weigh < shortpath[n] && flag[n] == 0 )
				    {
					    shortpath[n] = s->weigh;
					    point[n] = minp;
				    }
				s = s->next;
       		   }
			}
	}
	}
	printf("%d",sum);
}

int main(void)
{
//	clock_t start, finish;     //定义第一次调用CPU时钟单位的实际,可以理解为定义一个计数器
//	double Total_time;        //定义一个double类型的变量,用于存储时间单位
//	start = clock();        //获取进入要测试执行时间代码段之前的CPU时间占用值
//	
    int numvex,numedg;
    scanf("%d %d",&numvex,&numedg);
    creat_graph(numvex,numedg);
//    printf("\n");
//    print_graph(numvex);
    prim(numvex);
//    
//    finish = clock();
//    Total_time = (double)(finish - start);
//    printf("\n函数运行时间:%0.3f毫秒 \n", Total_time);
    return 0;
 } 

更改历程:

1、答案错误:因为链表创建的图为有向图,因而把将所有有联系的表反过来再连一遍

2、答案正确:运行超时

改为邻接矩阵重做

#include<stdio.h>
#include<stdlib.h>
#define maxvex 605
#define maxedg 200005
#define maxlen 65535
//邻接矩阵 
int acrs[maxvex][maxvex];
//阵创建 
void creat_zhen(int numvex,int numedg)
{
	for(int i = 0;i <= numvex;i++)
	{
		for(int j = 0;j <= numvex;j++)
		{
			acrs[i][j] = maxlen;
			if(i == j) acrs[i][j] = 0;
		}
	}
	for(int i = 0;i < numvex;i++)
	{
		int m;
		scanf("%d",&m);
		acrs[i][numvex] = m;
		acrs[numvex][i] = m;
	}
	for(int i = 0;i < numedg;i++)
	{
		int u,v,w;
		scanf("%d",&u);
		scanf("%d",&v);
		scanf("%d",&w);
		acrs[u][v] = w;
		acrs[v][u] = w;
	}
}
//阵打印:
void print_zhen(int numvex)
{
	for(int i = 0;i <= numvex;i++)
	{
		for(int j = 0;j <= numvex;j++)
		{
			printf("%d ",acrs[i][j]);
		}
		printf("\n");
	}
 } 
void prim(int numvex)
{
	int lowcost[numvex];
//	int flag[numvex];//表示已选点阵营所选点 
	int min;
	int mind;
	int sum = 0;
	for(int i = 1;i < numvex ;i++)
	{
	    lowcost[i] = acrs[0][i];
//		flag[i] = 1;
	}
	lowcost[0] = 0;
//	flag[0] = 0;
	for(int i = 1;i < numvex;i++)
	{
		min = maxlen;
		for(int j = 1;j < numvex;j++)
		{
			if(lowcost[j] < min&&lowcost[j] != 0)
			{
				min = lowcost[j];
				mind = j;
			}
		}
		sum += min;
		lowcost[mind] = 0;
		for(int i = 0;i < numvex;i++)
		{
			if(acrs[mind][i] < lowcost[i]&&acrs[mind][i] != 0)
			{
				lowcost[i] = acrs[mind][i];
//				mst[i] = mind;
			}
		 } 
	}
	printf("%d",sum);
} 
 int main(void)
 {
 	int numvex,numedg;
 	scanf("%d%d",&numvex,&numedg);
 	creat_zhen(numvex,numedg);
// 	print_zhen(numvex);
    numvex++;
    prim(numvex);
 	return 0;
 }

发现问题:lowcost数组(对应shortpath数组)本身即可表示点是否已经访问,通过是否为0判断;

 (

prim只适用于无向图,仅需要最小生成树权值——只需要一个数组

                                    还需要生成树路径——再加一个存储当前节点的数组

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值