poj 2421 (最小生成树 Prime+kruskal)

来源:互联网 发布:弗莱贝格工业大学 知乎 编辑:程序博客网 时间:2024/05/13 12:21
Constructing Roads
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 22145 Accepted: 9440

Description

There are N villages, which are numbered from 1 to N, and you should build some roads such that every two villages can connect to each other. We say two village A and B are connected, if and only if there is a road between A and B, or there exists a village C such that there is a road between A and C, and C and B are connected. 

We know that there are already some roads between some villages and your job is the build some roads such that all the villages are connect and the length of all the roads built is minimum.

Input

The first line is an integer N (3 <= N <= 100), which is the number of villages. Then come N lines, the i-th of which contains N integers, and the j-th of these N integers is the distance (the distance should be an integer within [1, 1000]) between village i and village j. 

Then there is an integer Q (0 <= Q <= N * (N + 1) / 2). Then come Q lines, each line contains two integers a and b (1 <= a < b <= N), which means the road between village a and village b has been built.

Output

You should output a line contains an integer, which is the length of all the roads to be built such that all the villages are connected, and this value is minimum.

Sample Input

30 990 692990 0 179692 179 011 2

Sample Output

179

Source


点击打开题目链接http://poj.org/problem?id=2421


题意:给出n,n个村庄,然后给你n*n的矩阵,表示i村庄到j村庄的距离,下面给的是Q对数据,表示啊a,b之间已经建好了路,不必再建。

分析: 把已经建过的路看作0,用Prime即可求出,Kruskal则把已经建好路的村庄归为用一集合;


Prime:

#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <algorithm>#include <math.h>typedef long long ll;using namespace std;#define INF 0x3f3f3f3f#define N 110int maps[N][N],vis[N],dis[N];int n,m,q;void init(int n){    int i,j;    for(i=0;i<=n;i++)        for(j=0;j<=n;j++)        maps[i][j]=(i==j)?0:INF;}int Prime(int s){    int i,j,index,Min,sum=0;    for(i=1;i<=n;i++)    {        dis[i]=maps[1][i];        vis[i]=0;    }    vis[s]=1;    for(i=1;i<=n;i++)    {        Min=INF,index=-1;        for(j=1;j<=n;j++)        {            if(!vis[j] && Min>dis[j])            {                Min=dis[j];                index=j;            }        }        if(index==-1)            break;        sum=sum+Min;        vis[index]=1;        for(j=1;j<=n;j++)        {            if(!vis[j] && dis[j]>maps[index][j])                dis[j]=maps[index][j];        }    }    return sum;}int main(){    int i,j,x,a,b;    while(scanf("%d",&n)!=EOF)  ///这里记住以EOF结束,以n!=0,则TLE;    {        init(n);        for(i=1;i<=n;i++)        {            for(j=1;j<=n;j++)            {                scanf("%d",&x);                maps[i][j]=maps[j][i]=x;            }        }        scanf("%d",&q);        while(q--)        {            scanf("%d%d",&a,&b);            maps[a][b]=maps[b][a]=0;  ///把已经建好的路赋值为0;        }        int ans=Prime(1);        printf("%d\n",ans);    }    return 0;}



Kruskal:

#include <iostream>#include <stdio.h>#include <string.h>#include <queue>#include <algorithm>#include <stdlib.h>#include <math.h>typedef long long ll;using namespace std;#define INF 0x3f3f3f3f#define N 11000int father[N];int maps[110][110];struct node{    int s,e,w;}p[N];int cmp(node a,node b)  ///排序,按照路径的由短到长排序{    return a.w<b.w;}int Find(int x)  ///查找父节点...{    while(x!=father[x])        x=father[x];    return x;}int main(){    int n,m,i,j,ans,a,b,x;    while(scanf("%d",&n)!=EOF)    {        for(i=1;i<=n;i++)  ///初始化。父节点为其本身            father[i]=i;        for(i=1;i<=n;i++)        {            for(j=1;j<=n;j++)            {                scanf("%d",&x);                maps[i][j]=x;            }        }        int num=0;        for(i=2;i<=n;i++)  ///注意循环条件 ,目的是把他们存入结构体P中。        {            for(j=1;j<i;j++)            {                p[num].s=i;                p[num].e=j;                p[num].w=maps[i][j];                num++;            }        }        scanf("%d",&m);        while(m--)        {            scanf("%d%d",&a,&b);            int x,y;            x=Find(a);            y=Find(b);            if(x!=y)               father[y]=x;  ///已经建好路的,归为同一集合        }        sort(p,p+num,cmp); ///路径按从小到大 排序        ans=0;        for(i=0;i<num;i++)        {            int x,y;            x=Find(p[i].s);            y=Find(p[i].e);            if(x==y)                continue;            else            {                ans=ans+p[i].w;                father[x]=y;            }        }        printf("%d\n",ans);    }    return 0;}



看了人家的代码才知道自己有多水,注意代码风格的培养,简洁的代码,才是大牛的作风....


下面的附录是一位大牛的代码:(借鉴借鉴  毕竟太菜......)

#include<iostream>using namespace std;int a[101][101],n,father[101],m,x,y;int get_father(int p){  return father[p]=(father[p]==p? p:get_father(father[p]));}int main(){  cin>>n;  for(int i=0;i<n;i++)    for(int j=0;j<n;j++)      cin>>a[i][j];  for(int i=0;i<n;i++)father[i]=i;  cin>>m;  for(int i=0;i<m;i++){    cin>>x>>y;    father[get_father(x-1)]=get_father(y-1);  }  int sum=0;  for(int k=1;k<=1000;k++)    for(int i=0;i<n;i++)      for(int j=0;j<n;j++)      if(a[i][j]==k&&get_father(i)!=get_father(j)){      sum+=a[i][j];      father[father[i]]=father[j];      }  cout<<sum<<endl;  return 0;}


0 0