3026 Borg Maze BFS+prim

/*

 

题目:

   就是所在矩形中有一些外星人,一些人组队打怪去,可以分很多支队,问这些队一共所需的

   最少移动步数

 

分析:

   由于可以分很多队,所以可以看做是从起点出发求最小生成树(其实有无起点一样,MST肯定

   包括起点),于是问题转换为求最小生成树。怎样处理点与点之间的距离。其实每两个点之间

   肯定存在通路,而任两点之间的最小直接距离可以通过bfs求到,于是可以通过枚举所有的点

   (即外星人和起点)到另外的点(还是外星人和起点)的距离。具体实现看代码

 

*/

#include <iostream>

#include <cstring>

#include <cstdio>

#include <queue>

using namespace std;

#define X 102

int map[X][X],ma[X][X],dis[X],n,m,cnt;

int dir[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};//方向偏移量

char ch[X][X];

bool use[X][X],visit[X];

struct node        //结构体,记录队列中的坐标和移动了的步数

{

   int x,y,step;

};

bool check(int x,int y)//检查是否越界

{

   if(x<0||y<0||x>=n||y>=m)

      return false;

   return true;

}

void bfs(int x,int y)

{

   memset(use,false,sizeof(use));

   node cur;

   cur.x = x;

   cur.y = y;

   cur.step = 0;

   queue<node> q;     //入队

   q.push(cur);

   use[x][y] = true;

 

   int cx,cy,step;

   int px = x,py = y;

   while(!q.empty())

   {

      cur = q.front();   //队首出队

      q.pop();        //删除队首

 

      x = cur.x;

      y = cur.y;

      step = cur.step;

 

      if(ma[x][y]) //注意到图是无向图 ,ma数组记录的是该坐标下的目标图的顶点下标(从1开始)

         map[ ma[x][y] ][ ma[px][py] ] = map[ ma[px][py] ][ ma[x][y] ] = step;

      //map数组记录的是目标图中两顶点的距离

 

      for(int i=0;i<4;i++)

      {

         cx = x+dir[i][0];

         cy = y+dir[i][1];  //算出下一次到达的位置

         if(check(cx,cy)&&ch[cx][cy]!='#'&&!use[cx][cy])//没有越界,可走的,没走过的

         {

            use[cx][cy] = true;

            cur.x = cx;

            cur.y = cy;

            cur.step = step+1; //移动距离加一

            q.push(cur);    //入队

         }

      }

   }

}

void prim()        //求最小生成树,图为邻接矩阵map[][],prim标准模板

{

   int ans = 0,k,MIN;

   memset(visit,false,sizeof(visit));

 

   for(int i=1;i<=cnt;i++)

      dis[i] = map[i][1];

   visit[1] = true;

   for(int i=1;i<cnt;i++)

   {

      MIN = 10000000;

      for(int j=1;j<=cnt;j++)

         if(!visit[j]&&dis[j]<MIN)

            MIN = dis[k=j];

      ans += MIN;

      visit[k] = true;

      for(int j=1;j<=cnt;j++)  //松弛操作

         if(!visit[j])

            dis[j] = min(dis[j],map[k][j]);

   }

   cout<<ans<<endl;

}

int main()

{

   freopen("sum.in","r",stdin);

   freopen("sum.out","w",stdout);

   int t;

   cin>>t;

   while(t--)

   {

      cnt = 0;

      memset(ma,0,sizeof(ma));

      scanf("%d%d ",&m,&n);

      for(int i=0;i<n;i++)

      {

         gets(ch[i]);

         for(int j=0;j<m;j++)

            if(ch[i][j]=='A'||ch[i][j]=='S')

                ma[i][j] = ++cnt;        //记录目标图的顶点

      }

      for(int i=0;i<n;i++)

         for(int j=0;j<m;j++)

            if(ma[i][j])    //若为外星人所在位置或者起点

                bfs(i,j);

      prim();  //求最短路

   }

 

   return 0;

}

 

posted @ 2012-04-09 22:37  yejinru  阅读(161)  评论(0编辑  收藏  举报