题意:
在一个y行,x列的迷宫中,有可行走的通路空格‘ ‘,不可行走的墙’#’,还有两种英文字母A和S,现在从S出发,要求用最短的路径L连接所有字母,输出这条路径L的总长度。
先bfs求两两字母间最短路,作为图的边
然后用prim算法求图的最小生成树
prim算法(摘自百度百科):
算法描述
编辑
1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:V
new = {x},其中x为集合V中的任一节点(起始点),E
new = {},为空;
3).重复下列操作,直到V
new = V:
a.在集合E中选取权值最小的边<u, v>,其中u为集合V
new中的元素,而v不在V
new
集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合V
new中,将<u, v>边加入集合E
new中;
4).输出:使用集合V
new和E
new来描述所得到的
最小生成树。
代码:
#include<iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int R,C;
char grid[1000][1000];
int tag[1000][1000];
bool vis[1000][1000];
int len[1000][1000];
int mov[4][2] = {{1,0},{0,-1},{-1,0},{0,1}};
bool is_in[5000];
char temp[510];
struct node{
int r,c;
int step;
}s[5000];
void bfs(int u){
node t1,t2;
queue<node> q;
t1.r = s[u].r;
t1.c = s[u].c;
t1.step = 0;
vis[t1.r][t1.c] = true;
q.push(t1);
while(!q.empty()){
t1 = q.front();
q.pop();
int v = tag[t1.r][t1.c];
if(v!=-1){
len[u][v] = len[v][u] = t1.step;
}
for(int i=0;i<4;i++){
t2.r = t1.r + mov[i][0];
t2.c = t1.c + mov[i][1];
if(t2.r<R && t2.r>=0 && t2.c<C && t2.c>=0){
if(vis[t2.r][t2.c]==false && grid[t2.r][t2.c]!='#'){
vis[t2.r][t2.c] = true;
t2.step = t1.step + 1;
q.push(t2);
}
}
}
}
}
int main(){
int T,i,j,k;
scanf("%d",&T);
while(T--){
scanf("%d%d",&C,&R);
memset(tag,-1,sizeof(tag));
memset(len,-1,sizeof(len));
gets(temp);
for(i=0;i<R;i++){
gets(grid[i]);
}
k=1;
for(i=0;i<R;i++){
for(j=0;j<C;j++){
if(grid[i][j]=='S' || grid[i][j]=='A'){
s[k].r = i;
s[k].c = j;
tag[i][j]=k++;
}
}
}
for(i=1;i<k;i++){
memset(vis,false,sizeof(vis));
bfs(i);
}
memset(is_in,false,sizeof(is_in));
is_in[1] = true;
int ans = 0;
//求最小生成树
while(true){
int t = 1000000000;
int pos = -1;
for(i=1;i<k;i++){
if(is_in[i]){
for(j=1;j<k;j++){
//if(j == i) continue;
if(!is_in[j]){
if(t>len[i][j]){
t = len[i][j];
pos = j;
}
}
}
}
}
if(pos == -1) break;
is_in[pos] = true;
ans += t;
}
printf("%d\n",ans);
}
return 0;
}
wa了两次..之前用getchar()吃掉输入整数后面的换行不知道为啥wa..看disscus改成gets一个字符串就过了,是测试数据里有空格..然后数组改大就能过。