最小生成树的题俩算法,prim和kruskal,分别以以下两题为例(我不会说是在练prim的时候2122用prim死也不A。。)
2122的题意就不说了,很短很直接,用意思相当好懂的kruskal,也就是在保证没有环的前提下一直添入最短的边,所以说,排个序,判个环,连接一下,累加一下就可以啦~
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#define inf 999999999
using namespace std;
int father[1001];
int find(int x)
{
if(father[x]==x)return x;
father[x]=find(father[x]);
return father[x];
}
struct node
{
int s,t,c;
}way[10001];
int cmp(node a,node b)
{
return a.c<b.c;
}
int main()
{
int n,m;
int x,y;
while(scanf("%d%d",&n,&m)!=-1)
{
for(int i=0;i<n;i++)
father[i]=i;
for(int i=0;i<m;i++)
scanf("%d%d%d",&way[i].s,&way[i].t,&way[i].c);
sort(way,way+m,cmp);
int ans,t;
t=0;
ans=0;
for(int i=0;i<m;i++)
{
x=find(way[i].s);
y=find(way[i].t);
if(x!=y)
{
t++;
ans+=way[i].c;
father[x]=y;
}
}
if(t!=n-1)printf("impossible\n");
else
printf("%d\n",ans);
printf("\n");
}
return 0;
}
2485是要求已经生成的最小生成树里最大的那条边,设个临时变量,判断一下就好~
这道是用的prim,思想上说比kruskal曲折,不过如果图的边很多,用kruskal有风险,所以嘛,方法什么的,依情况定(虽然我一般都搞不清情况。。)
prim的话呢,就是从一个点开始,先找出与之相连的最短的那条边,这样便找到了第二个点,再以此类推找到后面的点,也就是找边,更新权值的过程,题目要的结果加上个判断,当然一个判定这个节点是否被访问过的visit数组当然不可少。
#include<stdio.h>
#define max 510
int init[max][max],dis[max],n;
bool visit[max];
int prim()
{
int temp=0,po;
visit[0]=true;
for(int i=0;i<n;i++)
dis[i]=init[0][i];
//printf("dis%d\n",visit[1]);
//每轮
for(int i=1;i<n;i++)
{
int min=65550;
for(int j=0;j<n;j++)
{
if(visit[j]==false&&dis[j]<min)
{
min=dis[j];
po=j;
}
}
visit[po]=true;
if(temp<min)
{
temp=min;
// printf("yes%d\n",temp);
}
//更新权值
for(int k=0;k<n;k++)
{
if(visit[k]==false&&dis[k]>init[po][k])
{
dis[k]=init[po][k];
//printf("no");
}
}
}
return temp;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
scanf("%d",&init[i][j]);
visit[j]=false;
}
printf("%d\n",prim());
}
return 0;
}