題意:在一個y行,x列的迷宮中,有可行走的通路空格‘ ‘,不可行走的牆’#’,還有兩種英文字母A和S,現在從S出發,要求用最短的路徑L連接所有字母,輸出這條路徑L的總長度。
先bfs求兩兩字母間最短路,作爲圖的邊
然後用prim算法求圖的最小生成樹
prim算法(摘自百度百科):
1).輸入:一個加權連通圖,其中頂點集合爲V,邊集合爲E;
2).初始化:Vnew = {x},其中x爲集合V中的任一節點(起始點),Enew = {},爲空;
3).重複下列操作,直到Vnew = V:
a.在集合E中選取權值最小的邊<u, v>,其中u爲集合V
new中的元素,而v不在V
new集合當中,並且v∈V(如果存在有多條滿足前述條件即具有相同權值的邊,則可任意選取其中之一);
b.將v加入集合Vnew中,將<u, v>邊加入集合Enew中;
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一個字符串就過了,是測試數據裏有空格..然後數組改大就能過。