poj3026 Borg Maze bfs+最小生成树 prim

                                POJ 3026

题目大意:

给你一个y*x的字符矩阵,A代表外星人,S代表起点。然后现在有一个团队从起点出发去找外星人。从起点出发或者找到一个外星人,这个团队就可以分成几个小团队然后分头去找。找完所有外星人花费的总距离是所有团队的距离之和。

然后问你,最小总距离话费是多少。(

这道题有个坑,会在输入x,y之后输入一大堆空格。(呵呵...)

比如第二个测试样例:

7 7
#####  
#AAA###
#    A#
# S ###
#     #
#AAA###
#####  
从起点出发分成两个团队,一个团队向下找找到棕色的A花费2距离,然后分成两个团队向左找到蓝色的A和向右找到绿色的A,分别花费1距离,所以向下找的团队总花费是2+1+1=4。然后看从起点出发向上找的团队,同样话费4距离找到红黑黄色A,这时在黄色的团队开始去找紫色的A,花费3距离。所以最后总话费为4+4+3=11。

大思路致

其实想想看,S是可以看成A的,因为它对求最小花费没影响。

因为起点不唯一(从任意的A出发开始找时距离都是从0开始算的),而且求最小总花费,那团队肯定是再找到一个A后,尽可能花费最少的距离去找到另外一个A。这样才能保证,最后的总花费是最少的。

所以我们就可以先将任意两个A(S也看成A)的最短距离求出来,然后找一条合适的路径使得总话费最少,但是要经过所有的A。那么这就是求最小生成树了。至于给了字符矩阵,然后求两个点的最短距离,就用bfs了。。

(刚开始用bfs姿势不对,我用两层for循环去找两个点的最短距离,忘记了一遍bfs就可以跑遍所有图。所以导致超时了。。。。bfs思想贯彻的还是不够深。。。!- -)

AC代码:

#include<stdio.h>
#include<iostream>
#include<map>
#include<string.h>
#include<queue>
using namespace std;
const int inf=99999999;
typedef pair<int,int>Pa;
map<Pa,int>M;
int dis[505][505];
int vis[505][505];
int lowcost[505];
char c[505][505];
int move[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};
int x,y;
struct Node
{
    int nx;
    int ny;
   

} node[105];
void bfs(Node st)
{
    memset(vis,0,sizeof(vis));
    queue<Node>Q;
    Q.push(st);
    vis[st.nx][st.ny]=1;
    while(!Q.empty())
    {
        Node top=Q.front();
        Q.pop();
        for(int i=0; i<4; i++)
        {
            int xx=top.nx+move[i][0];
            int yy=top.ny+move[i][1];
            if(xx>=1&&xx<=y&&yy>=1&&yy<=x&&c[xx][yy]!='#'&&!vis[xx][yy])
            {
                 vis[xx][yy]=vis[top.nx][top.ny]+1;
                if(c[xx][yy]=='A'||c[xx][yy]=='S')
                {
                    dis[M[make_pair(st.nx,st.ny)]][M[make_pair(xx,yy)]]=vis[xx][yy]-1;//起点标记的是一,因为起点不算距离,所以减去一个1
                     dis[M[make_pair(xx,yy)]][M[make_pair(st.nx,st.ny)]]=vis[xx][yy]-1;//无向
                }

                Node nnode;
                nnode.nx=xx;
                nnode.ny=yy;
                Q.push(nnode);
            }

        }

    }
    return ;

}
int prim(int num)
{
    for(int i=2; i<=num; i++)
    {
        lowcost[i]=dis[1][i];
        //cout<<lowcost[i]<<endl;
    }
    lowcost[1]=0;
    int sum=0;
    int minl;
    int id;
    for(int i=2; i<=num; i++)
    {
        minl=inf;
        for(int j=2; j<=num; j++)
        {
            if(lowcost[j]&&lowcost[j]<minl)
            {

                minl=lowcost[j];
                id=j;
            }
        }
        if(minl==inf)return -1;
        sum+=minl;
        lowcost[id]=0;
        for(int j=2; j<=num; j++)
        {
            if(lowcost[j]&&lowcost[j]>dis[id][j])
            {
                lowcost[j]=dis[id][j];
            }
        }


    }
    return sum;
}
int main()
{
    int t;
    while(~scanf("%d",&t))
    {
        while(t--)
        {
             M.clear();
            int num=1;
            Node st;
            scanf("%d%d",&x,&y);
            char cc=getchar();
            while(cc==' ')cc=getchar();//去掉空格
            for(int i=1; i<=y; i++)
            {
                for(int j=1; j<=x; j++)
                {
                    scanf("%c",&c[i][j]);
                    if(c[i][j]=='A'||c[i][j]=='S')
                    {
                        node[num].nx=i;
                        node[num].ny=j;
                        M[make_pair(i,j)]=num;
                        num++;

                    }
                }
                if(i!=y)getchar();
            }
            for(int i=1;i<num;i++)
            {
                bfs(node[i]);
            }
            /*for(int i=1;i<=num;i++)
            {
                for(int j=1;j<=num;j++)
                {
                    cout<<"dis"<<" "<<i<<" "<<j<<" "<<dis[i][j]<<endl;
                }
            }*/
            printf("%d\n",prim(num-1));
        }
    }
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值