题目:
样例
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只适用于无向图,仅需要最小生成树权值——只需要一个数组
还需要生成树路径——再加一个存储当前节点的数组
)