还是畅通工
题目描述
浙江大学研究生复试题:某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
输入
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
当N为0时,输入结束,该用例不被处理。
输出
对每个测试用例,在1行里输出最小的公路总长度。
样例输入
3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
0
样例输出
3
5
提示
非常典型的Prim基础算法,想考研这个都不太会做...非常慌,要先理解透彻,我觉得它是通过局部最优推出全体最优!!
#include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<iomanip> using namespace std; int n;//表示村庄(点)数量 int e[120][120], d[10000];//e用来存储各村庄(点)相通边长的情况,d用来存储权值 (即边的长度) bool vis[120];//用于判断走没走过 //Prim算法函数 void Prim() { int minn;//最小边的值,每次迭代均需更新 int i,j; //对边进行赋值 //对vis数组进行初始化,全部标记为没走过 for(i = 1; i <= n; i++) { d[i] = e[1][i]; //d[i]为点1到其他各点的距离 vis[i] = 0; } vis[1] = 1;//0没走过,1走过,此处从1开始 int cont = 1;//来限计数,只要走过n-1条即可联通全图,n个点,n-1条边 int sum = 0;//总距离 //开始迭代 while(cont < n) { minn=1000000;//每一次都要初始化 //for循环寻找权值的最小值 for(i = 1; i <= n; i++) { if(vis[i] == 0 && d[i] < minn) //这个点没走过,并且它的距离比最小值小 { minn = d[i]; //更新最小值 j = i; //标记是哪个点 } } vis[j] = 1, sum += d[j], cont++; //把该点变成1,禁止二次访问,总距离加上该长度,计数++ //再更新一遍最短路径,对应的就是P224的第二步的第一步 //我觉得这一步是核心,就是寻找到已经访问过的点到其余点的距离的最小值,即剩余点和已联通图的最小距离 for(i = 1; i <= n; i++) { if(vis[i] == 0 && d[i] > e[j][i]) d[i]=e[j][i]; } } cout<<sum<<endl; } //主函数 int main() { int m;//边 int u,v,w; while(cout<<"请输入点的个数: ") { cin>>n&&n != 0; m = ((n-1) * n) / 2; cout<<"请输入两个点和它们之间的距离:"; //初始化 for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if(i == j) e[i][j] = 0; //自己和自己是算作不连通的; else e[i][j] = e[j][i] = 19920603; //在初始化中,其他各点都算作联通 } } //建图 for(int i = 1; i <= m; i++) { cin >> u >> v >> w;//分别输入u和v表示村庄(点)编号,w表示建路的线长 e[u][v] = e[v][u] = w; //将联通路的长度赋值 } //调用Prim函数 Prim(); } return 0; }
浙公网安备 33010602011771号