您的位置:首页 > 其它

NYOJ 38(最小生成树)

2012-05-19 15:04 190 查看
原来是求二维数组的每行或者每列的最小值,不过需要主要的是如果是4个点,只需要3条边就可以完全连接起来了,所以只需要找3次就行了。4条边有一条边会重复,需要舍弃。

就用题目的测试数据比较,用二维数组保存点与点连接的距离。



就用i代表行,j代表列。会发现 i,j都是从第二行开始的。而且跟y=x 直线对称。为什么说只要找到每行或者每列的最小值就行了呢。假设最开始没有2这个点,此时1,3,4就是一个集合。然后新添加一个点2进去,此时的最短路径就是点2到这个集合的最短路径,然后看2能够跟集合里面的哪些点连接,测试数据表示能看出来跟1,3,4都连接,所以找出与1,3,4连接的最小值就行,就能够构成一个新的最小生成树。然后比较过一个就标记下,不再重复找,接下来代码就简单了。

//因为每个楼都在最小生成树中,因此无论从哪号楼拉线都没有区别,所以只要选最小那个值就行
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define inf 0x7FFFFFFF/*就是INT_MAX,四个字节,共32位,而每四位为一个十六进制为,因为存在计算机中为补码,所以最高四位是0111,即7*/
int map[501][501];//**二维数组标记地图**//
bool a[501];
int cmp(const void *a,const void *b)
{
return *(int *)a-*(int *)b;
}
int main()
{
int T,m,n;int i,j,k;int min,t,x,y,value,ans;int b[501];//**用一维数组a[i]用来标记第i个点是否被访问过**//
scanf("%d",&T);
while(T--)
{
memset(b,0,sizeof(b));
scanf("%d %d",&m,&n);
ans=0;
for(i=1;i<=m;i++)
for(j=1;j<=m;j++)
map[i][i]=inf;
for(i=1;i<=n;i++)
{
scanf("%d %d %d",&x,&y,&value);
map[x][y]=map[y][x]=value;//**把能够连接的线都用二维数组保存,并将二维数组赋值**//
}
for(i=0;i<m;i++)
scanf("%d",&b[i]);//**无论从哪号楼拉线都没有区别,所以只要选最小那个值就行**//
qsort(b,m,sizeof(int),cmp);
for(i=2;i<=m;i++)
a[i]=false;
a[1]=true;//**访问过了,标记true,表示不再访问**//
for(i=2;i<=m;i++)//**标记了就知道,i,j都是从2开始,并对称**//
{
min=inf;
for(j=2;j<=m;j++)
{
if(min>map[i][j]&&!(a[j]==true&&a[i]==true))//**找出最小权值,避免环路**//
{
min=map[i][j];
k=j;
}
}
//	for(j=2;j<=m;j++)//**为下一次循环做准备,重新初始化**//
//	a[j]=false;
a[k]=true;
if(min!=inf)
ans=ans+min;//**加上权值**//
//printf("%d\n",ans);
}
printf("%d\n",ans+b[0]);
system("pause");
}
return 0;
}


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