最优布线问题&普里姆算法
Time Limit:10000MS Memory Limit:65536K
Total Submit:274 Accepted:178
Case Time Limit:1000MS
Description
学校有n台计算机,为了方便数据传输,现要将它们用数据线连接起来。两台计算机被连接是指它们之间有数据线连接。由于计算机所处的位置不同,因此不同的两台计算机的连接费用往往是不同的。
当然,如果将任意两台计算机都用数据线连接,费用将是相当庞大的。为了节省费用,我们采用数据的间接传输手段,即一台计算机可以间接的通过若干台计算机(作为中转)来实现与另一台计算机的连接。
现在由你负责连接这些计算机,你的任务是使任意两台计算机都连通(不管是直接的或间接的)。
Input
输入文件
w
i
r
e
.
i
n
wire.in
wire.in,第一行为整数
n
n
n
(
2
<
=
n
<
=
100
)
(2<=n<=100)
(2<=n<=100),表示计算机的数目。此后的
n
n
n行,每行
n
n
n个整数。第
x
+
1
x+1
x+1行
y
y
y列的整数表示直接连接第
x
x
x台计算机和第
y
y
y台计算机的费用。
Output
输出文件
w
i
r
e
.
o
u
t
wire.out
wire.out,一个整数,表示最小的连接费用。
Sample Input
3
0 1 2
1 0 1
2 1 0
Sample Output
2(注:表示连接1和2,2和3,费用为2)
Hint
F
i
l
l
c
h
a
r
Fillchar
Fillchar
(
f
,
s
i
z
e
o
f
(
f
)
,
(f,sizeof(f),
(f,sizeof(f),$
7
f
)
7f)
7f) 把所有值赋值为最大
解题思路
算法分析&思想讲解:
P
r
i
m
Prim
Prim算法每次循环都将一个蓝点
u
u
u变为白点,并且此蓝点
u
u
u与白点相连的最小边权
m
i
n
[
u
]
min[u]
min[u]还是当前所有蓝点中最小的。这样相当于向生成树中添加
n
−
1
n-1
n−1次最小的边,最后得到的一定是最小生成树。
初始时所有点都是蓝点,
m
i
n
[
1
]
=
0
,
m
i
n
[
2
、
3
、
4
、
5
]
=
min[1]=0,min[2、3、4、5]=
min[1]=0,min[2、3、4、5]=无穷大。权值之和
=
0
=0
=0。
第一次循环自然是找到min[1]=0最小的蓝点1。将1变为白点,接着枚举与1相连的所有蓝点2、3、4,修改它们与白点相连的最小边权。
m
i
n
[
2
]
=
a
[
1
]
[
2
]
=
2
;
min[2]=a[1][2]=2;
min[2]=a[1][2]=2;
m
i
n
[
3
]
=
a
[
1
]
[
3
]
=
4
;
min[3]=a[1][3]=4;
min[3]=a[1][3]=4;
m
i
n
[
4
]
=
a
[
1
]
[
4
]
=
7
;
min[4]=a[1][4]=7;
min[4]=a[1][4]=7;
m
i
n
[
5
]
=
∞
;
min[5]=∞;
min[5]=∞;
第二次循环是找到min[2]最小的蓝点2。将2变为白点,接着枚举与2相连的所有蓝点3、5,修改它们与白点相连的最小边权。
m
i
n
[
3
]
=
a
[
2
]
[
3
]
=
1
;
min[3]=a[2][3]=1;
min[3]=a[2][3]=1;
m
i
n
[
5
]
=
a
[
2
]
[
5
]
=
2
;
min[5]=a[2][5]=2;
min[5]=a[2][5]=2;
第三次循环是找到min[3]最小的蓝点3。将3变为白点,接着枚举与3相连的所有蓝点4、5,修改它们与白点相连的最小边权。
m
i
n
[
4
]
=
w
[
3
]
[
4
]
=
1
;
min[4]=w[3][4]=1;
min[4]=w[3][4]=1;
由于
m
i
n
[
5
]
=
2
<
w
[
3
]
[
5
]
=
6
;
min[5]=2 < w[3][5]=6;
min[5]=2<w[3][5]=6;所以不修改
m
i
n
[
5
]
min[5]
min[5]的值。
注意:这里是指一个蓝点到白点集合的最短距离,不是道一个白点的距离。
例:3到白点集合的最短距离为1。
代码
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n,a[200][200],minn[200],v[200],ans,k;//minn存放蓝点i到白点的最短距离,v标记i是否已经加入最小生成树
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
cin>>a[i][j];
}
memset(minn,0X7f,sizeof(minn));//初始设为无穷大
minn[1]=0;
for(int i=1;i<=n;i++)//要连n个点
{
k=0;
for(int j=1;j<=n;j++)//找一个与白点相连的权值最小的蓝点k
{
if(!v[j]&&minn[j]<minn[k])
k=j;
}
v[k]=1;
for(int j=1;j<=n;j++)//修改与k相连的所有蓝点
{
if(a[k][j]<minn[j]&&!v[j])
minn[j]=a[k][j];
}
}
for(int i=1;i<=n;i++)
ans+=minn[i];
cout<<ans;
}