N个村庄,从1到N编号,现在请您兴建一些路使得任何两个村庄彼此连通。我们称村庄A和B是连通的,当且仅当在A和B之间存在一条路,或者存在一个存在C,使得A和C之间有一条路,并且C和B是连通的。
已知在一些村庄之间已经有了一些路,您的工作是再兴建一些路,使得所有的村庄都是连通的,并且兴建的路的长度是最小的。
输入格式:
第一行是一个整数N(3<=N<=100),代表村庄的数目。后面的N行,第i行包含N个整数,这N个整数中的第j个整数是第i个村庄和第j个村庄之间的距离,距离值在[1,1000]之间。
然后是一个整数Q(0<=Q<=N*(N+1)/2)。后面给出Q行,每行包含两个整数a和b(1<=a<b<=N),表示在村庄a和b之间已经兴建了路。
输出格式:
输出一行仅有一个整数,表示为使所有的村庄连通需要新建公路的长度的最小值。
输入样例:
3
0 990 692
990 0 179
692 179 0
1
1 2
输出样例:
179
#include<bits/stdc++.h>
using namespace std;
const int MAXE = 10010,MAXV = 101,INF = INT_MAX;
int g[MAXV][MAXV],f[MAXV],n,cnt;
struct edge{
int u,v,w;
}e[MAXE];
bool cmp(edge a,edge b){
return a.w<b.w;
}
int find(int x){
if(x!=f[x]) f[x] = find(f[x]);
return f[x];
}
int krus(){
int ans = 0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(g[i][j]){//转化为结构体
e[cnt].u = i;
e[cnt].v = j;
e[cnt].w = g[i][j];
cnt++;
}
}
}
sort(e,e+cnt,cmp);
for(int i=0;i<cnt;i++){
if(find(e[i].u)!=find(e[i].v)&&g[e[i].u][e[i].v]!=0){
f[find(e[i].u)] = e[i].v;
ans += e[i].w;
}
}
return ans;
}
int main()
{
cin>>n;
for(int i=1; i<=n; i++) f[i] = i;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
cin>>g[i][j];
int q; cin>>q;
while(q--){
int a,b; cin>>a>>b;
f[find(a)] = find(b);
g[a][b] = g[b][a] = 0;
}
cout<<krus();
return 0;
}
// const int N = 101,INF = INT_MAX;
// int g[N][N],d[N],n;
// bool st[N];
// int prim(int s){
// fill(d,d+n,INF);
// d[s] = 0;
// int ans = 0;
// for(int i=1; i<=n; i++){
// int u = -1,MIN = INF;
// for(int j=1; j<=n; j++){
// if(!st[j] && d[j]<MIN){
// u = j;
// MIN = d[j];
// }
// }
// if(u==-1) return -1;
// st[u] = true;
// ans += d[u];
// for(int v=1; v<=n; v++){
// if(!st[v] && g[u][v]<d[v])
// d[v] = g[u][v];
// }
// }
// return ans;
// }
// int main()
// {
// cin>>n;
// for(int i=1; i<=n; i++)
// for(int j=1; j<=n; j++)
// cin>>g[i][j];
// int q; cin>>q;
// while(q--){
// int a,b; cin>>a>>b;
// g[a][b] = g[b][a] = 0;
// }
// cout<<prim(1);
// return 0;
// }