Description
大家都知道最小生成树一般求的是构成最小生成树的边的权值之和。
现在请求构成最小生成树的边的权值之积 S,最终结果请输出 (S % 100003)。
P.S. 点之间的边为无向边,矩阵保证符合无向图的对称性。
Input
多组数据。
第一行,整数N,表示N个点。(0 < N <= 100)
接下来为一个N*N 保证合法的邻接矩阵,矩阵内均为自然数。
Output
每组数据输出一行整数结果。
Sample Input
3
0 1 2
1 0 3
2 3 0
2
0 5
5 0
Prim
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 5 #define MAX 105 6 #define INF 0x7FFFFFFF 7 int map[MAX][MAX]; // adjacency matrix 8 bool vis[MAX]; // is the node i visited 9 int dis[MAX]; // distance between current node and other node i 10 11 void prim(int n) { 12 memset(vis, false, sizeof(vis)); 13 14 // current node is 0 15 int cur = 0; 16 for (int i = 0; i < n; ++i) 17 dis[i] = map[cur][i]; // dis[] store distance between other nodes and 0 18 vis[cur] = true; 19 20 unsigned long long s = 1; 21 for (int i = 0; i < n - 1; ++i) { 22 // find the shortest edge between cur and other unvisited nodes 23 int min = INF; 24 for(int j = 0; j < n; ++j) 25 if (!vis[j] && dis[j] < min) 26 min = dis[cur = j]; // update to next shortest edge and potential cur 27 28 // the other end is visited and is now current node 29 s *= min; 30 s %= 100003; 31 vis[cur] = true; 32 33 // update dis[] to store distance between other nodes and cur 34 // if the node is visited, leave it 35 for (int j = 0; j < n; ++j) 36 if (!vis[j] && map[cur][j] < dis[j]) 37 dis[j] = map[cur][j]; 38 } 39 cout << (s % 100003) << endl; 40 } 41 42 int main() { 43 int n; 44 45 while(scanf("%d", &n) != EOF) { 46 for (int i = 0; i < n; ++i) 47 for (int j = 0; j < n; ++j) 48 scanf("%d", &map[i][j]); 49 prim(n); 50 } 51 52 return 0; 53 }
Kruskal,其实改装成了边表,加了并查集,有做路径压缩,可以水过就懒得写带rank的优化了……
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 #define MAX 105 7 #define INF 0x7FFFFFFF 8 9 int root[MAX]; 10 int map[MAX][MAX]; 11 12 struct Edge { 13 int u, v; 14 int d; 15 } e[MAX*MAX]; 16 17 bool cmp(Edge a, Edge b) { 18 return a.d < b.d; 19 } 20 21 int find(int x) { 22 while(x != root[x]) { 23 root[x] = root[root[x]]; // compress 24 x = root[x]; 25 } 26 return x; 27 } 28 29 unsigned long long kruskal(int vn, int en) { 30 unsigned long long p = 1; 31 32 // connect to itself 33 for (int i = 0; i < vn; ++i) 34 root[i] = i; 35 36 // sort edges by length 37 std::sort(e, e+en, cmp); 38 39 for(int i = 0; i < en; ++i) { 40 int ru = find(e[i].u); 41 int rv = find(e[i].v); 42 if(ru != rv) { // the ends of e[i] are not in the same spanning tree 43 root[ru] = rv; // merge 44 p *= e[i].d; 45 p %= 100003; 46 } 47 } 48 49 return p; 50 } 51 52 int main() { 53 int vn; 54 while(cin >> vn) { 55 memset(map, 0, sizeof(map)); 56 for(int i = 0; i < vn; ++i) 57 for(int j = 0; j < vn; ++j) 58 cin >> map[i][j]; 59 60 int en = 0; 61 for(int i = 0; i < vn; ++i) // use upper-right corner 62 for(int j = i + 1; j < vn; ++j) { 63 // transform to adjacency list 64 e[en].u = i; 65 e[en].v = j; 66 e[en].d = map[i][j]; 67 ++en; 68 } 69 cout << kruskal(vn, en) % 100003 << ' '; 70 } 71 return 0; 72 }
因为数据太大所以每次乘完都要取模,不然会溢出。
因为本来就给的是邻接矩阵,kruskal要多做一步处理转换成边表,速度大约是prim的一半