POJ3026BFS+pirm
题目分析
本题给出一个迷宫,在有字母的点可以任意分头行动,问从S点出发遍历所有的A点最短距离是多少
思路:对S点+所有A点进行BFS求出最短距离,然后建图求最小生成树即可。任意两点之间均为直接相连的,稠密图,所以选择prim
需要注意的点是,输入的空格和数组开大的问题,详见讨论区
第一次写bfs的时候每次bfs只对固定的起点和终点计算,然后建图的时候得枚举所有的起点终点点对,重复计算量很大,tle了,后来改成枚举所有起点,一次bfs把其他的点都搞定
代码
#include<stdio.h>
#include<queue>
#include<vector>
#include<string.h>
using namespace std;
const int MAXN = 550;
const int MAXM = 1050;
const int INF = 0x3f3f3f;
int N,x,y;
char mat[MAXN][MAXN];
int dirx[4] = {1,-1,0,0},diry[4] = {0,0,1,-1};
int vis[MAXN][MAXN],dis[MAXM][MAXM],vst[MAXM],lowc[MAXM];
vector<int> xxx,yyy;
bool check(int xx,int yy){
return (mat[xx][yy]!='#' && xx>0 && xx<=y && yy>0 && yy<=x && !vis[xx][yy]);
}
//int bfs(int xx,int yy,int xxx,int yyy){
// memset(vis,0,sizeof(vis));
// queue<int> aa,bb;
// aa.push(xx);bb.push(yy);
// vis[xx][yy] = 1;
// while(!aa.empty()){
// int tempa = aa.front(),tempb = bb.front();
// //printf("%d,%d:%c\n",tempa,tempb,mat[tempa][tempb]);
// aa.pop();bb.pop();
// if(tempa == xxx && tempb == yyy) return vis[xxx][yyy]-1;
// for(int i = 0;i < 4;i++){
// int qa = tempa + dirx[i],qb = tempb + diry[i];
// if(check(qa,qb)){
// vis[qa][qb] = vis[tempa][tempb]+1;
// aa.push(qa);bb.push(qb);
// }
// }
// }
// return -1;
//}
int bfs(int j){
memset(vis,0,sizeof(vis));
queue<int> aa,bb;
int xx = xxx[j];
int yy = yyy[j];
aa.push(xx);bb.push(yy);
vis[xx][yy] = 1;
while(!aa.empty()){
int tempa = aa.front(),tempb = bb.front();
//printf("%d,%d:%c\n",tempa,tempb,mat[tempa][tempb]);
aa.pop();bb.pop();
for(int i = 0;i < xxx.size();i++){
if(tempa == xxx[i] && tempb == yyy[i]){
dis[j][i] = vis[tempa][tempb]-1;
dis[i][j] = vis[tempa][tempb]-1;
}
}
for(int i = 0;i < 4;i++){
int qa = tempa + dirx[i],qb = tempb + diry[i];
if(check(qa,qb)){
vis[qa][qb] = vis[tempa][tempb]+1;
aa.push(qa);bb.push(qb);
}
}
}
return -1;
}
int prim(int mat1[][MAXM],int n){
int sum = 0;
memset(vst,0,sizeof(vst));
memset(lowc,INF,sizeof(lowc));
vst[0] = 1;
for(int i = 0;i < n;i++){
lowc[i] = mat1[0][i];
}
for(int i = 1;i < n;i++){
int min = INF;
int p = -1;
for(int j = 0;j < n;j++){
if(!vst[j] && lowc[j] < min){
min = lowc[j];
p = j;
}
}
if(p == -1) return -1;
sum += min;
vst[p] = 1;
lowc[p]= 0;
for(int j = 0;j < n;j++){
if(!vst[j] && mat1[p][j] < lowc[j])
lowc[j] = mat1[p][j];
}
}
return sum;
}
int main(){
scanf("%d",&N);
char ch[15];
while(N--){
while(!xxx.empty()){
xxx.pop_back();
yyy.pop_back();
}
int sx = -1,sy = -1;
scanf("%d%d",&y,&x);
gets(ch);//处理样例输入空格,会读入换行符
for(int i = 1;i <= x;i++){
for(int j = 1;j <= y+1;j++){
mat[i][j]=getchar();
if(mat[i][j] == 'S') {
sx = i;
sy = j;
xxx.push_back(i);
yyy.push_back(j);
}
else if(mat[i][j] == 'A'){
xxx.push_back(i);
yyy.push_back(j);
}
}
}
memset(dis,0,sizeof(dis));
for(int i = 0;i <xxx.size();i++){
bfs(i);
}
// for(int i = 0;i < aa.size();i++){
// int tmp = bfs(sx,sy,aa[i],bb[i]);
// dis[0][i+1] = tmp;
// dis[i+1][0] = tmp;
// for(int j = 0;j < aa.size();j++){
// if(j == i) continue;
// if(dis[i+1][j+1]!=0) continue;
// int tmp = bfs(aa[j],bb[j],aa[i],bb[i]);
// dis[i+1][j+1] = tmp;
// dis[j+1][i+1] = tmp;
// }
// }
// for(int i = 0;i <= aa.size();i++){
// for(int j = 0;j <= aa.size();j++){
// printf("%d ",dis[i][j]);
// }
// printf("\n");
// }
printf("%d\n",prim(dis,xxx.size()));
// for(int i = 1;i <= x;i++){
// for(int j = 1;j <= y+1;j++){
// printf("%c",mat[i][j]);
// }
// }
// printf("%d",bfs(3,6,4,3));
}
}
6072K 188MS