您的位置:首页 > 其它

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

2011-02-17 22:41 393 查看
最小生成树的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
;

int e_num,n,m,head
,vis
,dist
;

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;
}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息