poj3026:http://poj.org/problem?id=3026
题意:在一个y行 x列的迷宫中,有可行走的通路空格’ ‘,不可行走的墙’#’,还有两种英文字母A和S,现在从S出发,要求用最短的路径L连接所有字母,输出这条路径L的总长度。
题解:一格的长度为1,而且移动的方法只有上、下、左、右,所以在无任何墙的情况下(根据题意的“分离”规则,重复走过的路不再计算因此当使用prim算法求L的长度时,根据算法的特征恰好不用考虑这个问题(源点合并很好地解决了这个问题),L就是最少生成树的总权值W由于使用prim算法求在最小生成树,因此无论哪个点做起点都是一样的,(通常选取第一个点),因此起点不是S也没有关系所以所有的A和S都可以一视同仁,看成一模一样的顶点就可以了剩下的问题关键就是处理 任意两字母间的最短距离,由于存在了“墙#” ,这个距离不可能单纯地利用坐标加减去计算,必须额外考虑,推荐用BFS(广搜、宽搜),这是本题的唯一难点,因为prim根本直接套用就可以了。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm>s 5 #include<queue> 6 #include<string> 7 #define INF 10000000 8 using namespace std; 9 int xn,yn,top,pos; 10 int n,m; 11 char map[56][56]; 12 int dist[56][56],lowcost[2505],g[2504][2506],visit[56][56]; 13 struct Node{ 14 int x; 15 int y; 16 int step; 17 }; 18 struct Node1{ 19 int x; 20 int y; 21 }node[2503]; 22 void init(){ 23 for(int i=1;i<=xn;i++) 24 for(int j=1;j<=yn;j++) 25 dist[i][j]=INF; 26 memset(visit,0,sizeof(visit)); 27 } 28 void bfs(Node1 a){ 29 init(); 30 dist[a.x][a.y]=0; 31 queue<Node>Q; 32 Node temp; 33 temp.x=a.x; 34 temp.y=a.y; 35 temp.step=0; 36 visit[a.x][a.y]=true; 37 Q.push(temp); 38 while(!Q.empty()){ 39 Node tmp=Q.front(); 40 Q.pop(); 41 int x=tmp.x; 42 int y=tmp.y; 43 if(x>=2&&map[x-1][y]!='#'&&!visit[x-1][y]){ 44 visit[x-1][y]=true;//bfs收索时候,一定要在入队之前标记,如果在出队 45 dist[x-1][y]=tmp.step+1;//时在标记,会使得一个元素在队列中可能会被加入多次。 46 temp.x=x-1; 47 temp.y=y; 48 temp.step=tmp.step+1; 49 Q.push(temp); 50 } 51 if(x<xn&&map[x+1][y]!='#'&&!visit[x+1][y]){ 52 visit[x+1][y]=true; 53 dist[x+1][y]=tmp.step+1; 54 temp.x=x+1; 55 temp.y=y; 56 temp.step=tmp.step+1; 57 Q.push(temp); 58 } 59 if(y>=2&&map[x][y-1]!='#'&&!visit[x][y-1]){ 60 visit[x][y-1]=true; 61 dist[x][y-1]=tmp.step+1; 62 temp.x=x; 63 temp.y=y-1; 64 temp.step=tmp.step+1; 65 Q.push(temp); 66 } 67 if(y<yn&&map[x][y+1]!='#'&&!visit[x][y+1]){ 68 visit[x][y+1]=true; 69 dist[x][y+1]=tmp.step+1; 70 temp.x=x; 71 temp.y=y+1; 72 temp.step=tmp.step+1; 73 Q.push(temp); 74 } 75 } 76 } 77 void prim(int v0){ 78 int sum=0; 79 for(int i=1;i<top;i++){ 80 lowcost[i]=g[v0][i]; 81 } 82 lowcost[v0]=-1; 83 for(int i=1;i<top-1;i++){ 84 int min=INF; 85 int v=-1; 86 for(int j=1;j<top;j++){ 87 if(lowcost[j]<min&&lowcost[j]!=-1){ 88 min=lowcost[j]; 89 v=j; 90 } 91 } 92 if(v!=-1){ 93 sum+=lowcost[v]; 94 lowcost[v]=-1; 95 for(int k=1;k<top;k++) 96 if(lowcost[k]!=-1&&g[v][k]<lowcost[k]) 97 lowcost[k]=g[v][k]; 98 } 99 } 100 printf("%d ",sum); 101 } 102 int main(){ 103 int cas;string line; 104 scanf("%d",&cas); 105 char sss[30]; 106 while(cas--){ 107 top=1; 108 scanf("%d%d",&yn,&xn); 109 gets(sss);//这里如果用gethchar()oj会判wa 110 for(int i=1;i<=xn;i++){ 111 getline(cin,line);//读取一整行 112 113 for(int j=1;j<=yn;j++){ 114 map[i][j]=line[j-1]; 115 if(map[i][j]!=' '&&map[i][j]!='#'){//记录每个A和S 116 node[top].x=i; 117 node[top++].y=j; 118 } 119 if(map[i][j]=='S'){//记录起点 120 pos=top-1; 121 } 122 } 123 } 124 for(int i=1;i<top;i++){ 125 bfs(node[i]);//一遍bfs找出了所有其他点与改点的距离 126 for(int j=i+1;j<top;j++){//建边 127 g[i][j]=g[j][i]=dist[node[j].x][node[j].y]; 128 } 129 } 130 for(int i=1;i<top;i++)//初始化 131 for(int j=1;j<top;j++){ 132 if(i==j)g[i][j]=0; 133 else if(g[i][j]==0)g[i][j]=INF; 134 } 135 prim(pos); 136 } 137 }