Sakura晞月

导航

还是畅通工

题目描述

浙江大学研究生复试题:某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。

输入

测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当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;
}

 

 

posted on 2018-05-30 20:19  Sakura晞月  阅读(186)  评论(1)    收藏  举报