poj3026

题目大意:让你求从S点到A点的所能达到的最小距离。

算法思路:先通过bfs求出各个字母之间的最短距离,再求最小生成树。

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
#define INF 0x3f3f3f3f

typedef struct Node
{
    int x,y;
    int lev;
    int sym;
};
Node nodes[3000];
char a[300][300];
int edges[300][300];
int dist[3000];
int t;
int n,m,ssym,num,sum;
int dx[4]={-1,0,1,0};
int dy[4]={0,-1,0,1};
bool visited[300][300],visited2[3003];
int xb[300][300];
void bfs(Node node)
{
    memset(visited,false,sizeof(visited));
    queue<Node>que;
    que.push(node);
    visited[node.x][node.y]=true;
    while(!que.empty())
    {
        Node cur=que.front();
        que.pop();
        for(int i=0;i<4;i++)
        {
            int nx=cur.x+dx[i];
            int ny=cur.y+dy[i];
            if(1<=nx&&nx<=n&&1<=ny&&ny<=m&&!visited[nx][ny]&&a[nx][ny]!='#')
            {
                if(a[nx][ny]=='A'||a[nx][ny]=='S')
                {
                    edges[node.sym][nodes[xb[nx][ny]].sym]=cur.lev+1;
                }
                Node flag;
                flag.x=nx;
                flag.y=ny;
                flag.lev=cur.lev+1;
				visited[nx][ny]=true;
                que.push(flag);
            }
        }
    }


}
void prim()
{
    sum=0;
	int i,j;
    memset(dist,0x3f,sizeof(dist));
    memset(visited2,false,sizeof(visited2));
    for(i=1;i<num;i++)
    {
        dist[i]=edges[1][i];
    }
    visited2[1]=true;

    for(i=1;i<num;i++)
    {
        int MIN=INF,node=-1;
        for(j=1;j<num;j++)
        {
            if(!visited2[j]&&dist[j]<MIN)
            {
                MIN=dist[j];
                node=j;
            }
        }

        if(node==-1)
            return;
        visited2[node]=true;
        sum+=dist[node];

        for(j=1;j<num;j++)
        {
            if(!visited2[j]&&dist[j]>edges[node][j])
            {
                dist[j]=edges[node][j];
            }
        }


    }



}
int main()
{
    scanf("%d",&t);
	int i,j;
    while(t--)
    {
        memset(nodes,0,sizeof(nodes));
        memset(xb,0,sizeof(xb));
        memset(edges,0,sizeof(edges));
        num=1;
        scanf("%d%d",&m,&n);
        for(i=0;i<=n;i++)
        {
           gets(a[i]+1);
        }

        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++)
            {
                if(a[i][j]=='S')
                {
                    Node node;
                    node.x=i;
                    node.y=j;
                    node.lev=0;
                    ssym=num;
                    node.sym=num;
                    xb[i][j]=num;
                    nodes[num++]=node;
                }
                else if(a[i][j]=='A')
                {
                    Node node;
                    node.x=i;
                    node.y=j;
                    node.lev=0;
                    node.sym=num;
                    xb[i][j]=num;
                    nodes[num++]=node;
                }
            }
        }

        for(i=1;i<=num;i++)
        {
             bfs(nodes[i]);
        }

        prim();

        printf("%d\n",sum);

    }


}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值