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.
题意:
先输入N,再输入N*N阶邻接矩阵。
邻接矩阵表示i到j的距离。
然后输入q表示有q组是连接着的,
然后输入q行,每行两个数字,表示i与j连接
求 要把n个都连接需要的最短距离。
这里使用普里姆Prim,即使用邻接矩阵。
Sample Input
3
0 990 692
990 0 179
692 179 0
1
1 2
Sample Output
179
基本思想:将顶点之间连接权值存在一个二维数组中,没有连接两个顶点之间为极大值,循环访问所有顶点,如已经得到该顶点与其它顶点连接的最小权值,则将其标记为1,不做重复访问。
代码实现:
#include<iostream>
#include<cstring>
using namespace std;
const int N=110;
const int INF=0x3f3f3f3f; //表示无穷大。
int n,result;
int map[N][N],dis[N],vis[N];
void Prim()
{
int i;
for(i=1; i<=n; i++)
{
dis[i]=map[1][i];
vis[i]=0;
}
dis[1]=0;
vis[1]=1;
int j,k,tmp;
for(i=1; i<=n; i++)
{
tmp=INF;
for(j=1; j<=n; j++)
if(!vis[j]&&tmp>dis[j])
{
k=j;
tmp=dis[j];
}
if(tmp==INF)
break;
vis[k]=1;
result+=dis[k];
for(j=1; j<=n; j++)
if(!vis[j]&&dis[j]>map[k][j])
dis[j]=map[k][j];
}
}
int main()
{
while(cin>>n)
{
int i,j;
for(i=1; i<=n; i++)
for(j=1; j<=n; j++)
cin>>map[i][j];
int q,a,b;
cin>>q;
while(q--)
{
cin>>a>>b;
map[a][b]=map[b][a]=0;
}
result=0;
Prim();
cout<<result<<endl;
}
return 0;
}
1、0x3f3f3f3f的十进制是1061109567,也就是10的9次方级别的(和0x7fffffff一个数量级),而一般场合下的数据都是小于10^9的,所以它可以作为无穷大使用而不致出现数据大于无穷大的情形。
2、由于一般的数据都不会大于10^9,所以当我们把无穷大加上一个数据时,它并不会溢出,这就满足了“无穷大加一个有穷的数依然是无穷大”,事实上0x3f3f3f3f+0x3f3f3f3f=2122219134,这非常大但却没有超过32-bit int的表示范围,所以0x3f3f3f3f还满足了我们“无穷大加无穷大还是无穷大”的需求。
3、0x3f3f3f3f还有一个好处:如果我们想要将某个数组清零,我们通常会使用memset(a,0,sizeof(a))这样的代码来实现,但是当我们想将某个数组全部赋值为无穷大时(例如解决图论问题时邻接矩阵的初始化),就不能使用memset函数而得自己写循环了,这是因为memset是按字节操作的,它能够对数组清零是因为0的每个字节都是0。如果我们将无穷大设为0x3f3f3f3f,0x3f3f3f3f的每个字节都是0x3f,所以要把一段内存全部置为无穷大,我们只需要memset(a,0x3f,sizeof(a))。