C++,电话连线【普里姆算法,最小生成树】
题目描述 Description
一个国家有n个城市。若干个城市之间有电话线连接,现在要增加m条电话线(电话线当然是双向的了),使得任意两个城市之间都直接或间接经过其他城市有电话线连接,你的程序应该能够找出最小费用及其一种连接方案。
输入描述 Input Description
输入文件的第一行是n的值(n<=100).
第二行至第n+1行是一个n*n的矩阵,第i行第j列的数如果为0表示城市i与城市j有电话线连接,否则为这两个城市之间的连接费用(范围不超过10000)。
输出描述 Output Description
输出文件的第一行为你连接的电话线总数m,第二行至第m+1行为你连接的每条电话线,格式为i j,(i<j), i j是电话线连接的两个城市。输出请按照Prim算法发现每一条边的顺序输出,起始点为1.
第m+2行是连接这些电话线的总费用。
样例输入 Sample Input
5
0 15 27 6 0
15 0 33 19 11
27 33 0 0 17
6 19 0 0 9
0 11 17 9 0
样例输出 Sample Output
2
1 4
2 5
17
数据范围及提示 Data Size & Hint
n<=100
———————————————————————————————————————————————————————————————————————————————————————————
思想:基本的做法和之前写过的普里姆算法求最小生成树的一样,下面写的题解是在那基础之上修改的。
不同点,更新每个蓝点到白点集团的最小距离时,更新它的father点fa[i]
#include<iostream> #include<cstring> using namespace std; int main(){ int n,i,j,k,cnt=0,ans=0; int e[101][101];//邻接矩阵存边 int minn[101];//每个蓝点到白点集团的最小值 bool u[101];//标记已加入生成树的点为白点(0),没加入的为蓝点(1) int fa[101];//存白点的father点 int que[101];//存有father点的白点,这里往下看就明白了 memset(u,1,sizeof(u));//先将所有点标记为蓝点 memset(fa,1,sizeof(fa));//将所有点的father点设为起点1 memset(minn,0x7f,sizeof(minn));//将所有蓝点到白点集团的最小值初始化为maxint minn[1]=0;//1设为第一个白点 cin>>n; for(i=1;i<=n;i++) for(j=1;j<=n;j++) cin>>e[i][j]; for(i=1;i<=n;i++){ k=0; for(j=1;j<=n;j++) if(u[j]&&minn[j]<minn[k]){ k=j; }//找出当前距离白点集团最近的蓝点 u[k]=0; ans+=minn[k]; que[cnt]=k;//把这个点存入输出que里 if(minn[k]!=0&&minn[k]!=0x7f) cnt++;//如果当前加入que的点是本来没有连上线的点,才算作新加入的点,cnt++ for(j=1;j<=n;j++) if(u[j]&&e[k][j]<minn[j]){ minn[j]=e[k][j]; if(minn[j]!=0&&minn[j]!=0x7f){ fa[j]=k;//当一个点的最小值更新的时候,同时更新它的father点 } } } cout<<cnt<<endl; for(i=0;i<cnt;i++){ if(fa[que[i]]<que[i]) cout<<fa[que[i]]<<" "<<que[i]<<endl; else cout<<que[i]<<" "<<fa[que[i]]<<endl; } cout<<ans; return 0; }