一、Prim算法
参考之前的博文:http://www.cnblogs.com/Oloo/articles/3631631.html
二、问题描述
2485和1258题目基本一致,唯一的区别就是2485需要注意的一个地方,不然会耗时很长,详见下面的注意。
3026题相比上两题来说,多了一个困难就是构造图,边的权重需要我们想办法求出来。参见下面的问题分析。
POJ 2485:http://poj.org/problem?id=2485
POJ 1258:http://poj.org/problem?id=1258
POJ 3026:http://poj.org/problem?id=3026
前两道题题意一看就知道是MST,后一道题想一下也就是知道是MST。题意就不赘述了。
三、问题分析
MST需要分析的问题,之前的博文已经分析过了。这里只分析3026中边权重求解。
答:看到测试样例,我们第一反应就是迷宫题,迷宫题离不开搜索。后面看到从S出发,要求找到所有的A,并且,在初始点和A点处可以分支,并且要求所有分支的路径和最短,这就可以将这个问题看做MST问题。在使用Prim之前,目前我们需要解决的问题就剩下了边权重的计算。我们分析之后,清楚我们要知道任意一点到其他点的距离。于是立马可以想到可以使用BFS来解决。
四、程序实现
POJ 1258:
1 #include<iostream> 2 #include <cstdio> 3 using namespace std; 4 #define INF 100000000 5 6 int N; //#vallege 7 int edges[102][102]; 8 int values[102]; 9 10 void input() 11 { 12 for(int i = 0;i < N;i++) 13 for(int j = 0;j < N;j++) 14 scanf("%d" , &edges[i][j]); 15 for(int i = 0;i < N;i++) values[i] = edges[0][i]; 16 } 17 18 int MST_Prim() 19 { 20 int res = 0; 21 for(int k = 0; k < N;k++) 22 { 23 int index = -1;int min = INF; 24 for(int i = 0;i < N;i++) 25 { 26 if(min > values[i] && values[i] >= 0) 27 { 28 min = values[i]; 29 index = i; 30 } 31 } 32 values[index] = -1; 33 res += min; 34 for(int j = 0;j < N;j++) 35 if(edges[index][j] != 0 && edges[index][j] < values[j]) 36 values[j] = edges[index][j]; 37 } 38 return res; 39 } 40 int main() 41 { 42 while(cin >> N) 43 { 44 input(); 45 cout<<MST_Prim()<<endl; 46 } 47 return 0; 48 }
POJ 2485:
1 #include<iostream> 2 #include <cstdio> 3 using namespace std; 4 #define INF 100000000 5 6 int N; //#vallege 7 int edges[502][502]; 8 int values[502]; 9 10 void input() 11 { 12 scanf("%d" , &N); 13 for(int i = 0;i < N;i++) 14 for(int j = 0;j < N;j++) 15 scanf("%d" , &edges[i][j]); 16 for(int i = 0;i < N;i++) values[i] = edges[0][i]; 17 } 18 19 int MST_Prim() 20 { 21 int res = 0; 22 for(int k = 0; k < N;k++) 23 { 24 int index = -1;int min = INF; 25 for(int i = 0;i < N;i++) 26 { 27 if(min > values[i] && values[i] >= 0) 28 { 29 min = values[i]; 30 index = i; 31 } 32 } 33 values[index] = -1; 34 if(res < min) res = min; 35 for(int j = 0;j < N;j++) 36 if(values[j] >= 0 && edges[index][j] < values[j]) 37 values[j] = edges[index][j]; 38 } 39 return res; 40 } 41 int main() 42 { 43 int T; 44 scanf("%d" , &T); 45 if(T != 0) 46 while(T--) 47 { 48 input(); 49 cout<<MST_Prim()<<endl; 50 } 51 return 0; 52 }
POJ 3026:
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 using namespace std; 5 #define INF 10000000 6 7 struct point 8 { 9 int px,py; 10 int d; 11 } points[102]; 12 13 int x,y,num;//input y行x列 aliens'num 14 //****BFS***** 15 char map[52][52];//储存迷宫地图 16 int visit[52][52]; 17 queue<point> q;//BFS 18 int flag[552]; 19 int direct[4][2] = {{1,0},{0,1},{-1,0},{0,-1}}; 20 //*****Prim***** 21 int edges[102][102];//记录edges[i]记录i到其他所有点的距离 22 int values[102];//Prim中点权重记录 23 24 void input() 25 { 26 num = 0; 27 for(int i = 0;i < y;i++) 28 { 29 gets(map[i]); 30 for(int j = 0;j < x;j++) 31 if(map[i][j] == 'A' || map[i][j]=='S') 32 { 33 points[num].px = i; 34 points[num].py = j; 35 points[num].d = 0; 36 flag[i*10+j] = num; 37 values[num] = INF; 38 if(map[i][j] == 'S') values[num] = 0; 39 num++; 40 } 41 } 42 } 43 44 void BFS(int u) 45 { 46 for(int i = 0;i < num;i++) 47 points[i].d = 0; 48 point t;int time = 0; 49 q.push(points[u]); 50 while(!q.empty()) 51 { 52 point p = q.front(); 53 q.pop(); 54 //判断是否为A或者S 55 if(map[p.px][p.py] == 'A' || map[p.px][p.py]=='S') 56 { 57 edges[u][flag[p.px*10+p.py]] = p.d; 58 time++; 59 } 60 visit[p.px][p.py] = 1; 61 //将合法的四个方向压入q 62 for(int i = 0;i < 4;i++) 63 { 64 int xx = p.px + direct[i][0]; 65 int yy = p.py + direct[i][1]; 66 if(map[xx][yy] != '#' && !visit[xx][yy]) 67 { 68 visit[xx][yy] = 1; //这句话导致了TLE 69 t.px = xx; 70 t.py = yy; 71 t.d = p.d+1; 72 q.push(t); 73 } 74 } 75 } 76 } 77 78 void countEdges() 79 { 80 for(int i = 0; i < num;i++) 81 { 82 memset(visit , 0 ,sizeof(visit)); 83 BFS(i); 84 } 85 } 86 87 int MST_Prim() 88 { 89 int sum = 0; 90 for(int k = 0;k < num;k++) 91 { 92 int index = -1;int min = INF; 93 for(int i = 0;i < num;i++) 94 if(values[i] >= 0 && min > values[i]) 95 { 96 min = values[i]; 97 index = i; 98 } 99 values[index] = -1; 100 sum += min; 101 for(int i = 0;i < num;i++) 102 if(edges[index][i] != 0 && edges[index][i] < values[i]) 103 values[i] = edges[index][i]; 104 } 105 return sum; 106 } 107 108 int main() 109 { 110 int T = 0;char c[51]; 111 cin >> T; 112 while(T--) 113 { 114 cin >> x >> y; 115 gets(c); 116 input(); 117 countEdges(); 118 cout<<MST_Prim()<<endl; 119 } 120 return 0; 121 }
五、注意
1、 POJ 2485中在接收输入的时候,第一次使用了cin,结果时间惨不忍睹,后来看到题目里的HINT之后,使用了scanf,发现确实快,后来上网看了一下,scanf貌似确实比cin快,cin貌似要同步什么东东,导致了本来比scanf快的cin变慢了,可以用一条代码取消同步,将cin变快,我只能表示,之前一直写java,做android和web开发的孩子对C++的各种机制不是很了解,这里做一个备注吧,不再深究了。
2、 POJ 3026,由上面的问题分析知道,我们可以使用BFS+MST-PRIM来解决,这里记个小备注,我在使用BFS的时候翻了一个低级的错误,那就是将邻接的点压入队列的时候,忘了将其标志位置位,导致了BFS运行异常慢。
3、POJ 3026,输入数据存在trick,会多出很多的空格,注意使用gets()就好
六、感想
自己通过自己独立分析问题,自己独立编程实现,最后这个题目AC,这个节奏还是很好的~
最后,YZY,我想你!~
浙公网安备 33010602011771号