POJ 3026 Borg Maze (Prim Algorithm)

题目链接:
POJ 3026 Borg Maze
题意:
有一个n行*m列的字符矩阵,A代表一个需要同化的点,S代表起始点,#代表障碍,不可通过,‘ ’空格是可行的。
从s开始需要同化所有的A,并且一个A被同化后也具有了同化其他A的能力。输入保证S可到达任意一个A。
问从s开始同化所有的A需要多少步?
分析:
将所有的A和S看成一个个点,也就是求将这些点连通的最小生成树。
然后问题就是任意两点间的权值,并且这个权值是两点间所有可达路径中的最短路径。
对每一个点用一次BFS就好了,再用Prim Algorithm就行了。
注意:
n,m后面可能不止一个空格,太坑了……

//840K 110MS
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;

const int maxn=150;
const int INF=0x3f3f3f3f;

int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//上下左右四个方向

int T,n,len,tot;
int cost[maxn][maxn],vis[maxn][maxn],dis[maxn],vvis[maxn];
char map[maxn][maxn],s[maxn];

struct Point{
    int x,y;
}point[maxn];

struct Node{
    int x,y,step;
}cur,nextnode;

void bfs(int u,int sr,int sc)//u,sr,sc分别是点编号和点所在行列
{
    queue<Node> q;
    cur.x=sr;
    cur.y=sc;
    cur.step=0;
    memset(vis,0,sizeof(vis));//标记图上各点访问情况
    vis[cur.x][cur.y]=1;
    cost[u][u]=0;
    q.push(cur);
    while(!q.empty())
    {
        cur=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            int x=cur.x+dir[i][0];
            int y=cur.y+dir[i][1];
            if(x<0||y<0||x>=n||y>=len||vis[x][y]||map[x][y]=='#') continue;
            //printf("%d %d\n",x,y);
            nextnode.x=x;
            nextnode.y=y;
            nextnode.step=cur.step+1;
            vis[x][y]=1;
            for(int j=0;j<tot;j++)
            {//因为图上每个可访问点都只访问一次,所以访问到一个点就是两点间的距离
                if(point[j].x==x&&point[j].y==y)
                {
                    cost[u][j]=nextnode.step;
                }
            }
            q.push(nextnode);
        }
    }
}


int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    scanf("%d",&T);
    while(T--)
    {
        tot=1;
        scanf("%d%d",&len,&n);
        for(int i=0;i<n;i++)
        {
            gets(s);//一开始这里写getchar();结果WA了,看Discuss才知道原来后台数据len,n后面还有空格
            for(int j=0;j<len;j++)
            {
                scanf("%c",&map[i][j]);
                if(map[i][j]=='A')
                {
                    point[tot].x=i;
                    point[tot].y=j;
                    tot++;
                }
                else if(map[i][j]=='S')//起点下标为0
                {
                    point[0].x=i;
                    point[0].y=j;
                }
            }
        }
        /*
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<len;j++)
            {
                putchar(map[i][j]);
            }
            printf("\n");
        }
        */
        for(int i=0;i<tot;i++)//对每一点求相应边长,由于起点可到达任意一点,那么任意两点间都是连通的
            bfs(i,point[i].x,point[i].y);

        /*
        for(int i=0;i<tot;i++)
        {
            for(int j=0;j<tot;j++)
            {
                printf("%d ",cost[i][j]);
            }
            printf("\n");
        }
        */

        //Prim Algorithm
        memset(vvis,0,sizeof(vvis));
        vvis[0]=1;
        int ans=0;
        for(int i=0;i<tot;i++)//一共有tot个点
            dis[i]=cost[0][i];
        for(int i=1;i<tot;i++)
        {
            int k=-1;
            int tmp=INF;
            for(int j=0;j<tot;j++)
            {
                if(!vvis[j]&&dis[j]<tmp)
                {
                    k=j;
                    tmp=dis[j];
                }
            }
            vvis[k]=1;
            ans+=tmp;
            for(int j=0;j<tot;j++)
            {
                if(!vvis[j]&&dis[j]>cost[k][j]) dis[j]=cost[k][j];
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值