# Agri-Net - POJ 1258 最小生成树

Agri-Net
 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 36534 Accepted: 14713

Description

Farmer John has been elected mayor of his town! One of his campaign promises was to bring internet connectivity to all farms in the area. He needs your help, of course.
Farmer John ordered a high speed connection for his farm and is going to share his connectivity with the other farmers. To minimize cost, he wants to lay the minimum amount of optical fiber to connect his farm to all the other farms.
Given a list of how much fiber it takes to connect each pair of farms, you must find the minimum amount of fiber needed to connect them all together. Each farm must connect to some other farm such that a packet can flow from any one farm to any other farm.
The distance between any two farms will not exceed 100,000.

Input

The input includes several cases. For each case, the first line contains the number of farms, N (3 <= N <= 100). The following lines contain the N x N conectivity matrix, where each element shows the distance from on farm to another. Logically, they are N lines of N space-separated integers. Physically, they are limited in length to 80 characters, so some lines continue onto others. Of course, the diagonal will be 0, since the distance from farm i to itself is not interesting for this problem.

Output

For each case, output a single integer length that is the sum of the minimum length of fiber required to connect the entire set of farms.

Sample Input

4
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0


Sample Output

28

Source

给你N*N矩阵，表示N个村庄之间的距离。FJ要把N个村庄全都连接起来，求连接的最短距离。（即传说中的最小生成树）
样例分析：
连接方式：1-----------2-----------3----------4
距离：                 4      +       8     +        16         =                  24

图论之最小生成树问题。。。下面的是Prime算法复杂度O(n*n)
最小生成树算法思想：
假设N=(V,E) 是连通网,TE是N上最小生成树中边的集合,算法从U={vk},TE={ }开始(即从vk出发求最小生成树,vk∈V)。
重复执行下述操作：
在所有的边(vi,vj)∈E (vi∈U,vj∈V-U)中寻找一条权值最小的边(vi,vj)将其添加到TE中(或打印之),同时把vj添 加到集合U 中 。
反复执行上述操作n-1次（或所有顶点全部加入U时为止）。
通俗的说：1、有一个图N=（V，E），设置一个空集合U，设置路长ans=0。
2、就是先找一个点v1，将v1添加到集合U，再找出和它距离最近的点v2，再把v2添加到集合U，ans加上两点间的距离。
3、再到点集合V-U （属于V，但是不属于U的点）中找出一个离集合U最近的点。将找到的点添加到集合U，ans加上这个最短的距离。
4、如此循环第三步，直到所有的点全到U中。

a[][]为输入的矩阵,设一个数组d[]表示当前已连接的点的集合到还未连接的点的最小距离，每次的循环找到离当前已连接的点距离最近的点，对于最开始的时候让d[1]=0，其他为无穷大，使第一次循环的时候连接第一个点，（这句话看不懂可以先继续往下看），然后你现在已经连接了第一个点，那么你再连到其他点的距离就应该是a[1][j]，将其输入d[]中。第二次循环，找到d[]中最短的点，现在你已连接的点又多了一个，那么你这两个点再连接其他点的最短距离可能会更短，用d[j]=min(d[j],a[pos][j])修改d[]中的值，一直循环n次，每次连接1个点，直到连接了所有的点结束。
下面是AC代码：

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int a[110][110];         //a[][]为输入的矩阵
int n,ans;
int d[110];              //d[]为当前已连接的点的集合到还未连接的点的最小距离
int visit[110];          //visit[]标记已经连接的点
const int INF=100000000;
void Prime()
{ int i,j;
for(i=1;i<=n;i++)
d[i]=INF;
d[1]=0;               //对于最开始的时候让d[1]=0，其他为无穷大，使第一次循环的时候连接第一个点
memset(visit,0,sizeof(visit));
for(i=1;i<=n;i++)
{ int pos=INF,mi=INF; //pos为d[]表示的距离中距离最短的点的指针，mi表示最短的距离
for(j=1;j<=n;j++)   //找到该点
if(!visit[j] && d[j]<=mi)  //visit[]记录的已连接的点就不用考虑了
{ pos=j;
mi=d[j];
}
visit[pos]=1;       //该点已连接
ans+=mi;            //总的长度加上这个最短距离
for(j=1;j<=n;j++)   //现在你已连接的点（第pos个点）又多了一个，那么你再连接其他点的最短距离可能会更短
if(!visit[j])
d[j]=min(d[j],a[pos][j]);
}
}
int main()
{ int i,j,k;
while(~scanf("%d",&n))
{ for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%d",&a[i][j]);
ans=0;
Prime();
printf("%d\n",ans);
}
}