最小生成树算法
给定一个带权的无向连通图,如何选取一棵生成树,使树上所有边上权的总和为最小,这叫最小生成树.
1、克鲁斯卡尔算法
方法:将图中边按其权值由小到大的次序顺序选取,若选边后不形成回路,则保留作为一条边,若形成回路则除去.依次选够(n-1)条边,即得最小生成树.(n为顶点数)
克鲁斯卡尔法对于边特别多的情况,消耗时间比较多,不是很实用。
2、普里姆算法
方法:从指定顶点开始将它加入集合中,然后将集合内的顶点与集合外的顶点所构成的所有边中选取权值最小的一条边作为生成树的边,并将集合外的那个顶点加入到集合中,表示该顶点已连通.再用集合内的顶点与集合外的顶点构成的边中找最小的边,并将相应的顶点加入集合中,如此下去直到全部顶点都加入到集合中,即得最小生成树。
// In Practice, You should use the statndard input/output // in order to receive a score properly. // Do not use file input and output. Please be very careful. #include <cstdio> #include <iostream> #include <vector> using namespace std; #define INT_MAX 10000 int main(int argc, char** argv) { int tc, T; // The freopen function below opens input.txt file in read only mode, and afterward, // the program will read from input.txt file instead of standard(keyboard) input. // To test your program, you may save input data in input.txt file, // and use freopen function to read from the file when using cin function. // You may remove the comment symbols(//) in the below statement and use it. // Use #include<cstdio> or #include<stdio.h> to use the function in your program. // But before submission, you must remove the freopen function or rewrite comment symbols(//). // freopen("input.txt", "r", stdin); cin >> T; for(tc = 0; tc < T; tc++) { /********************************** * Implement your algorithm here. * ***********************************/ int N, i, j; int MAX_DISTANCE = 0; int arr[101][101]; scanf("%d",&N); for(i=1;i<=N;i++) for(j=1;j<=N;j++) { scanf("%d",&arr[i][j]); if(arr[i][j] > MAX_DISTANCE) MAX_DISTANCE = arr[i][j]; } vector<int> left; // 剩下的节点 vector<int> have; for (i = 2; i <= N; i++) //第一个节点不添加,默认第一次选中 left.push_back(i); have.push_back(1); int ans =0; while(0 != left.size()) { int min = MAX_DISTANCE; int k = 0; for(i =0; i < left.size(); i++) for(j = 0; j < have.size(); j++) { int a = left[i]; int b = have[j]; if(arr[a][b] > 0 && arr[a][b] < min) { min = arr[a][b]; k = i;//第i个元素需要从left中放入have } } ans += min; //cout<<"Now "<<left[k]<<" is linked and ans = "<<ans<<endl; have.push_back(left[k]); left.erase(left.begin()+k); } cout<<ans<<endl; // Print the answer to standard output(screen). } return 0;//Your program should return 0 on normal termination. }
上面代码就是利用普里姆算法算法实现最小生成树,第一实用vector,代码写的比较糟糕。