畅通工程
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 43016 Accepted Submission(s): 19231
Problem Description
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。
Input
测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
Output
对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
Sample Input
3 3 1 2 1 1 3 2 2 3 4 1 3 2 3 2 0 100
Sample Output
3 ?
Source
Recommend
lcy | We have carefully selected several similar problems for you: 1879 1233 1875 1232 1102
Prim
Prim算法用于构建最小生成树——即树中所有边的权值之和最小。例如,构建电路板,使所有边的和花费最少。只能用于无向图。因为最终求的是边到树集合的距离,树集合中的顶点无法再次遍历,所以只能应用与无向图
将顶点合成一颗树
//#include<bits/stdc++.h>
#include<cstdio>
#include<algorithm>
#include <string.h>
using namespace std;
#define inf 0x3f3f3f3f
#define M 105
int n,m;
int mat[M][M];
int prim(int m,int sta,int mat[][M]){//n表示有n个顶点,sta表示从sta这个顶点出发生成最小生成树 M表示存放的无向图
int sum=0;
int sum=0;
int i,j,flag;
int lowcost[M];
int u[M];//0表示不在树中,1表示在树中 s
//初始化
for(i=0;i<m;i++){
lowcost[i]=mat[sta][i]; // lowcost[i]记录图中的点到树顶点的最小权值 因为初始时只有一个点
u[i]=0;
}
u[sta]=1;//此时将sta加入树中
//因为最小树中会包含每个点,而每一次扫描会加入一条边,树集合中已经有一个初始顶点,所以这里扫描m-1次
for(i=1;i<m;i++){
//扫描到树中的顶点最小权值的点 使下一步能够将该点加入到树u中
int min=inf;//使min此时无穷大
for(j=0;j<m;j++)
if(!u[j]&&min>lowcost[j])
min=lowcost[j],flag=j;
if(min==inf) //此种情况图未联通,未联通的值为inf
return 0;
sum+=min;//记录最小的权值边 会记录顶点数量-1次
u[flag]=1;//将最小的点加入树集合中
//因为此时加入了新的树结点,所以lowcost的值也需要改变成到树顶点的最小权值
for( j=0;j<m;j++)
if(mat[flag][j]<lowcost[j])
lowcost[j]=mat[flag][j];
}
return sum;
}
int main(){
while(scanf("%d%d",&n,&m)&&n){
memset(mat,inf,sizeof(mat));
for(int i=0;i<n;i++){
int from,to,cost;
scanf("%d%d%d",&from,&to,&cost);
mat[from-1][to-1]=mat[to-1][from-1]=cost;
}
int ret=prim(m,0,mat);
if(ret==0){
printf("?\n");
}else{
printf("%d\n",ret);
}
}
return 0;
}
Kruskal
将森林合并成一个mnt(最小树)
使用并查集,关键是要将边排序
//#include<bits/stdc++.h>
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxsize 10001
int biaoji[maxsize];
int set2[maxsize];
int n,m; //n表示道路(边) m表示(顶点)村庄数目
struct edge{
int from,to;
long long cost;
}E[maxsize];
bool cmp(edge a,edge b){
return a.cost<b.cost;
}
void init(){
for(int i=0;i<maxsize;i++)
set2[i]=i;
}
int find(int i){
return set2[i]==i?i:set2[i]=find(set2[i]);
}
void merge(int a,int b){
if(find(a)==find(b))
return;
set2[find(a)]=find(b);
}
bool check(int a,int b){
return find(a)==find(b);
}
long long kruskal(){
long long reg=0;
sort(E+1,E+1+n,cmp);
for(int i=1;i<=n;i++){
if(check(E[i].from,E[i].to)) continue;
merge(E[i].from,E[i].to);
reg+=E[i].cost;
}
return reg;
}
int main(){
while(scanf("%d%d",&n,&m)==2){
if(n==0)
break;
init();
for(int i=1;i<=n;i++){
scanf("%d%d%lld",&E[i].from,&E[i].to,&E[i].cost);
}
long long ret=kruskal();
for(int i=1;i<=m;i++)
if(!check(1,i))
ret=-1;
if(ret==-1)
printf("?\n");
else
printf("%lld\n",ret);
}
return 0;
}