普里姆算法(Prim算法),圖論中的一種算法,可在加權連通圖里搜索最小生成樹。意即由此算法搜索到的邊子集所構成的樹中,不但包括了連通圖里的所有頂點,且其所有邊的權值之和亦為最小。該算法於1930年由捷克數學家沃伊捷赫·亞爾尼克發現;並在1957年由美國計算機科學家羅伯特·普里姆獨立發現;1959年,艾茲格·迪科斯徹再次發現了該算法。因此,在某些場合,普里姆算法又被稱為DJP算法、亞爾尼克算法或普里姆-亞爾尼克算法
算法過程圖解:遍歷點,用貪心法選擇與集合內的點相連的點的最小值;
模板:

1 #include <iostream> 2 #include <algorithm> 3 #include <cmath> 4 #include <cstdio> 5 #include <string> 6 #include <cstring> 7 #include <vector> 8 #include <queue> 9 #include <stack> 10 #include <set> 11 #define INF 0x3f3f3f3f 12 #define INFL 0x3f3f3f3f3f3f3f3f 13 #define zero_(x,y) memset(x , y , sizeof(x)) 14 #define zero(x) memset(x , 0 , sizeof(x)) 15 #define MAX(x) memset(x , 0x3f ,sizeof(x)) 16 using namespace std; 17 #define N 1005 18 typedef long long LL ; 19 int G[N][N]; 20 int minn[N];///尋找最小權; 21 bool point[N]; 22 23 int main(){ 24 //freopen("in.txt","r",stdin); 25 memset(point, 0, sizeof(point)); 26 int n, m, x, y, ans=0; 27 scanf("%d%d", &n, &m); 28 for(int i=1;i<=n;i++){ 29 for(int j = 1; j <= n; j++){ 30 G[i][j] = INF; 31 } 32 } 33 for(int i = 1; i <= m; i++) { 34 scanf("%d%d", &x, &y); 35 scanf("%d", &G[x][y]); 36 G[y][x] = G[x][y]; 37 } 38 point[1] = true; 39 for(int i = 1;i <= n; i++) minn[i] = G[1][i]; 40 for(int i = 1 ; i <= n; i++){ 41 int k = 0, mi = INF; 42 for(int j = 1; j <= n; j++){ 43 if(!point[j] && minn[j] < mi){ 44 mi = minn[j]; 45 k = j; 46 } 47 } 48 ans += minn[k]; 49 point[k] = true; 50 for(int s = 1;s <= n; s++){ 51 if(!point[s] && G[k][s] < minn[s])///保存了之前沒有加入集合的邊的權; 52 minn[s] = G[k][s]; 53 } 54 } 55 printf("%d\n", ans); 56 return 0; 57 }
題意:點是7位小寫字母,邊是小寫字母間的不同字母數量(1-7)。求最小生成樹。
邊權:the number of positions with different letters in truck type codes.

1 #include <iostream> 2 #include <algorithm> 3 #include <stdlib.h> 4 #include <time.h> 5 #include <cmath> 6 #include <cstdio> 7 #include <string> 8 #include <cstring> 9 #include <vector> 10 #include <queue> 11 #include <stack> 12 #include <set> 13 14 #define c_false ios_base::sync_with_stdio(false); cin.tie(0) 15 #define INF 0x3f3f3f3f 16 #define INFL 0x3f3f3f3f3f3f3f3f 17 #define zero_(x,y) memset(x , y , sizeof(x)) 18 #define zero(x) memset(x , 0 , sizeof(x)) 19 #define MAX(x) memset(x , 0x3f ,sizeof(x)) 20 #define swa(x,y) {LL s;s=x;x=y;y=s;} 21 using namespace std ; 22 #define N 2005 23 24 const double PI = acos(-1.0); 25 typedef long long LL ; 26 int n, dis[N][N], minn[N]; 27 char x[10]; 28 string type[N]; 29 bool point[N]; 30 31 int Distance(int i, int j){ 32 int len = 7, sum = 0; 33 for(int k = 0; k < len; k++) 34 if(type[i][k] != type[j][k]) 35 sum++; 36 return sum; 37 } 38 int prim(){ 39 point[1] = true; 40 int ans = 0; 41 for(int i = 1; i <= n; i++) minn[i] = dis[1][i]; 42 for(int i = 1; i <= n; i++){ 43 int k = 0; int mi =INF; 44 for(int j = 1; j <= n; j++){ 45 if(!point[j] && minn[j] <mi){ 46 mi = minn[j]; 47 k = j; 48 } 49 } 50 ans += minn[k]; 51 point[k] = true; 52 for(int s = 1; s <= n; s++){ 53 if(!point[s] && dis[k][s] <minn[s]) 54 minn[s] = dis[k][s]; 55 } 56 } 57 return ans; 58 } 59 int main(){ 60 //freopen("in.txt","r",stdin); 61 //freopen("out.txt","w",stdout); 62 //ios_base::sync_with_stdio(false); cin.tie(0); 63 while(~scanf("%d", &n) && n){ 64 zero(dis);zero(point);MAX(dis); 65 for(int i = 1; i <= n; i++){ 66 scanf("%s", x); 67 type[i] = x; 68 } 69 for(int i = 1; i<= n; i++){ 70 for(int j = 1; j < i; j++){ 71 dis[i][j] = dis[j][i] = Distance(i, j); 72 } 73 } 74 printf("The highest possible quality is 1/%d.\n", prim()); 75 } 76 return 0; 77 }
題意:求最小生成樹的最大邊權;(英語實在太爛)
point:minimize the length of the longest highway

1 #include <iostream> 2 #include <algorithm> 3 #include <stdlib.h> 4 #include <time.h> 5 #include <cmath> 6 #include <cstdio> 7 #include <string> 8 #include <cstring> 9 #include <vector> 10 #include <queue> 11 #include <stack> 12 #include <set> 13 14 #define c_false ios_base::sync_with_stdio(false); cin.tie(0) 15 #define INF 0x3f3f3f3f 16 #define INFL 0x3f3f3f3f3f3f3f3f 17 #define zero_(x,y) memset(x , y , sizeof(x)) 18 #define zero(x) memset(x , 0 , sizeof(x)) 19 #define MAX(x) memset(x , 0x3f ,sizeof(x)) 20 #define swa(x,y) {LL s;s=x;x=y;y=s;} 21 using namespace std ; 22 #define N 505 23 24 const double PI = acos(-1.0); 25 typedef long long LL ; 26 int T, n, dis[N][N], minn[N]; 27 bool point[N]; 28 29 int prim(){ 30 point[1] = true; 31 int ans = 0; 32 for(int i = 1; i <= n; i++) minn[i] = dis[1][i]; 33 for(int i = 1; i <= n; i++){ 34 int k = 0; int mi =INF; 35 for(int j = 1; j <= n; j++){ 36 if(!point[j] && minn[j] <mi){ 37 mi = minn[j]; 38 k = j; 39 } 40 } 41 if(ans < minn[k]) ans = minn[k]; 42 point[k] = true; 43 for(int s = 1; s <= n; s++){ 44 if(!point[s] && dis[k][s] <minn[s]) 45 minn[s] = dis[k][s]; 46 } 47 } 48 return ans; 49 } 50 51 int main(){ 52 //freopen("in.txt","r",stdin); 53 //freopen("out.txt","w",stdout); 54 //ios_base::sync_with_stdio(false); cin.tie(0); 55 scanf("%d", &T); 56 while(T--){ 57 zero(point);zero(dis);zero(minn); 58 scanf("%d", &n); 59 for(int i = 1; i <= n; i++){ 60 for(int j = 1; j <= n; j++){ 61 scanf("%d", &dis[i][j]); 62 } 63 } 64 printf("%d\n", prim()); 65 } 66 return 0; 67 }
簡單模板題,同上;

1 #include <iostream> 2 #include <algorithm> 3 #include <stdlib.h> 4 #include <time.h> 5 #include <cmath> 6 #include <cstdio> 7 #include <string> 8 #include <cstring> 9 #include <vector> 10 #include <queue> 11 #include <stack> 12 #include <set> 13 14 #define c_false ios_base::sync_with_stdio(false); cin.tie(0) 15 #define INF 0x3f3f3f3f 16 #define INFL 0x3f3f3f3f3f3f3f3f 17 #define zero_(x,y) memset(x , y , sizeof(x)) 18 #define zero(x) memset(x , 0 , sizeof(x)) 19 #define MAX(x) memset(x , 0x3f ,sizeof(x)) 20 #define swa(x,y) {LL s;s=x;x=y;y=s;} 21 using namespace std ; 22 #define N 505 23 24 const double PI = acos(-1.0); 25 typedef long long LL ; 26 int n, dis[N][N], minn[N]; 27 bool point[N]; 28 29 int prim(){ 30 point[1] = true; 31 int ans = 0; 32 zero(minn);zero(point); 33 for(int i = 1; i <= n; i++) minn[i] = dis[1][i]; 34 for(int i = 1; i <= n; i++){ 35 int k = 0; int mi =INF; 36 for(int j = 1; j <= n; j++){ 37 if(!point[j] && minn[j] <mi){ 38 mi = minn[j]; 39 k = j; 40 } 41 } 42 ans += minn[k]; 43 point[k] = true; 44 for(int s = 1; s <= n; s++){ 45 if(!point[s] && dis[k][s] <minn[s]) 46 minn[s] = dis[k][s]; 47 } 48 } 49 return ans; 50 } 51 52 int main(){ 53 //freopen("in.txt","r",stdin); 54 //freopen("out.txt","w",stdout); 55 //ios_base::sync_with_stdio(false); cin.tie(0); 56 while(~scanf("%d", &n) && n){ 57 zero(dis); 58 for(int i = 1; i <= n; i++){ 59 for(int j = 1; j <= n; j++){ 60 scanf("%d", &dis[i][j]); 61 } 62 } 63 printf("%d\n", prim()); 64 } 65 return 0; 66 }
題意:求最小生成樹;
思路:prim + BFS
這題的難點在於尋找鄰接矩陣;
用BFS 找到各點間的最小距離的點;
然后就是套模板;