一、Prim算法
算法描述:
算法过程与Dijskstra算法基本一致,只有一点不同,就是Dijskstra执行Relax操作的地方,使用相应的边的权重来更新相应点的D值。
参考《算法导论》23章最小生成树Prim算法部分
二、问题描述
POJ 1789:http://poj.org/problem?id=1789
卡车的牌照标识一般是从一种牌照演化到另一种,现在历史学家要研究牌照演化的进程,给定一组卡车牌照,写个程序帮历史学家找出牌照演化的最小生成树<详细见问题分析>。
四、问题分析
编程之前需要解决一个问题:
问题一、图的构造?
问题一:这道题目图的构造还是不算难的!以每种卡车牌照为节点,任意一种牌照到其他牌照都有边,边的权重,通过比较两种牌照之间相同位置的不同字符个数。
五、程序实现
1 #include<iostream> 2 #include<string> 3 #include <algorithm> 4 #define INF 1000 5 using namespace std; 6 7 int N;//卡车编号的个数 8 char strs[2001][8]; 9 bool flag[2001]; 10 int values[2001]; 11 12 int countD(int i , int j) 13 { 14 int sum = 0; 15 for(int k = 0;k < 7;k++) 16 if(strs[i][k] != strs[j][k]) 17 sum++; 18 return sum; 19 } 20 21 void input() 22 { 23 for(int i = 0;i < N;i++) 24 { 25 cin >> strs[i]; 26 } 27 for(int i = 0;i < N;i++) values[i] = INF; 28 values[0] = 0; 29 memset(flag,false,sizeof(flag)); 30 } 31 32 int MST_Prim() 33 { 34 int sum = 0; 35 for(int k = 0;k < N;k++) 36 { 37 int min = INF;int index = -1; 38 for(int i = 0;i < N;i++) 39 { 40 if(!flag[i] && min > values[i]) 41 { 42 min = values[i]; 43 index = i; 44 } 45 } 46 sum += min; 47 flag[index] = true; 48 for(int i = 0;i < N;i++) 49 { 50 if(!flag[i] && values[i] > countD(index,i)) 51 { 52 values[i] = countD(index,i); 53 } 54 } 55 } 56 return sum; 57 } 58 59 int main() 60 { 61 while(cin >> N) 62 { 63 if(N == 0) break; 64 input(); 65 cout<<"The highest possible quality is 1/"<<MST_Prim()<<"."<<endl; 66 } 67 return 0; 68 }
六、备注
这道题使用Prim的优势:
第一,Kruskal速度比prim慢,我实现的两者分别是500+MS和200+MS
第二,Prim可以不存储边,相当省内存,使用prim不存储边,最后用了240k内存,300+MS,对应Kruskal算法存储边使用了巨大的内存
七、感想
自己通过自己独立分析问题,自己独立编程实现,最后这个题目AC,这个节奏还是很好的~
最后,YZY,我想你!~
浙公网安备 33010602011771号