题意:
有一个n*m的图,有S,A,#和空格,S可以到达A并且使A变成S,然后这个S又可以去侵染别的A,问A都变成S需要多少步?
分析:
题目相当于求出S和A构成的最小生成树。首先把S和A找出来,枚举每个S和A,然后bfs求一下单点到其他点的最短距离,然后套prim模板就行。
这题有个特别坑的地方就是数字后面可等有多个空格,好坑!!!
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<stack> #include<map> #include<vector> #include<queue> using namespace std; #define mp make_pair const int INF=1000000000; const int N=500+9; typedef pair<int,int>pii; //点的坐标 <x,y> typedef pair<int,pii>piii; //<步数,点> int w[N][N],low[N]; bool vis[N][N]; char s[N][N]; int n,m; int dx[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; vector<pii>vec; //存S和A map<pii,int>id; //给每个S和A编一个号 int sid; void bfs(pii start) { queue<piii>q; memset(vis,0,sizeof(vis)); q.push(mp(0,start)); vis[start.first][start.second]=1; while(!q.empty()){ piii p=q.front();q.pop(); int step=p.first,x=p.second.first,y=p.second.second; for(int i=0;i<4;i++){ int xx=x+dx[i][0],yy=y+dx[i][1]; if(xx<0||yy<0||xx==n||yy==m||vis[xx][yy])continue; vis[xx][yy]=1; if(s[xx][yy]=='A'||s[xx][yy]=='S'){ w[id[mp(xx,yy)]][sid]=step+1;continue; } if(s[xx][yy]==' ')q.push(mp(step+1,mp(xx,yy))); } } } int prim(int n) { bool vis[111]; memset(vis,0,sizeof(vis)); vis[0]=1; int ans=0,p=0; for(int i=0;i<n;i++)low[i]=w[p][i]; for(int i=1;i<n;i++){ int minn=INF; for(int j=0;j<n;j++)if(!vis[j]&&minn>low[j])minn=low[p=j]; ans+=minn; vis[p]=1; for(int j=0;j<n;j++)if(!vis[j]&&low[j]>w[p][j])low[j]=w[p][j]; } return ans; } int main() { int T;scanf("%d",&T); while(T--){ scanf("%d%d",&m,&n); vec.clear(); id.clear(); gets(s[0]); //注意可能有多个空格 for(int i=0;i<n;i++){ gets(s[i]); for(int j=0;j<m;j++) if(s[i][j]=='A'||s[i][j]=='S')id[mp(i,j)]=vec.size(),vec.push_back(mp(i,j)); } for(int i=0;i<vec.size();i++)for(int j=0;j<vec.size();j++)w[i][j]=i==j?0:INF; for(int i=0;i<vec.size();i++){ sid=id[vec[i]]; bfs(vec[i]); } printf("%d ",prim(vec.size())); } return 0; }