poj2485
题目大意:有几个小岛,现要修路将其连接起来,求最长路的最小值。
题目分析:求生成树的最大边最小值。。。其实也是最小生成树的最大边,可用kruskal每次将最小边加进来,最后一条边就是最大边
#include<algorithm>
#include<iostream>
#include<stdio.h>
using namespace std;
int A[510][510],k,p[510];
int f(int x){ //并查集,判断边上的两点是否在同一个集合
if(x==p[x]) return x;
else return f(p[x]);
}
struct Q{
int x,y,v;
};
Q B[300000];
bool cmp(Q a,Q b){ return a.v<b.v;} //边排序
int krus(){
int u,v,max,i;
for(i=1;i<=k;i++){
u=f(B[i].x);
v=f(B[i].y);
if(u!=v){
p[u]=v;
max=B[i].v; //由于边已边排序,加进来的边也不断变大
}
}
return max;
}
int main(){
int t,n,i,j;
cin>>t;
while(t--){
scanf("%d",&n);
for(i=1;i<=n;i++){
p[i]=i;
for(j=1;j<=n;j++){
scanf("%d",&A[i][j]);
}
}
k=0;
for(i=1;i<=n;i++){
for(j=1+i;j<=n;j++){
k++;
B[k].v=A[i][j];
B[k].x=i;
B[k].y=j;
}
}
sort(B+1,B+k+1,cmp);
int m=krus();
printf("%d\n",m);
}
return 0;
}
hdoj3371
题目大意:有n个小岛,两个小岛间有的有路,有的没有,现要从m条可选的路中选择,将所有小岛都连接起来,求建路最小花费
思路分析:由于有的点间已经有路,可用并查集将它们并在一起,再对这m条可用边,依次从小到大选择判断边上的两点是否已在一个集合中
#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
int p[1000],m;
struct Q{
int x,y,v;
}A[300000];
bool cmp(Q a,Q b){ return a.v<b.v;}
int find(int a){
if(a==p[a]) return a;
else return find(p[a]);
}
int krus(){
int i,u,v,sum=0;
for(i=1;i<=m;i++){
u=find(A[i].x);
v=find(A[i].y);
if(u!=v){
p[u]=v;
sum+=A[i].v;
}
}
return sum;
}
int main(){
int t,n,i,k,a,b,j;
scanf("%d",&t);
while(t--){
for(i=1;i<=500;i++) p[i]=i;
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=m;i++) scanf("%d%d%d",&A[i].x,&A[i].y,&A[i].v);
for(i=1;i<=k;i++){
scanf("%d",&a);
scanf("%d",&b);
int x=find(b);
a--;
while(a--){
scanf("%d",&b);
int y=find(b); //将有路的点合并
if(y!=x) p[y]=x;
}
}
sort(A+1,A+m+1,cmp);
int ans=1,m=krus();
a=find(1);
for(i=1;i<=n;i++) if(find(i)!=a) ans=0; //判断所有点是否都已在一个集合中
if(ans) printf("%d\n",m);
else printf("-1\n");
}
return 0;
}