FZU - 2150 两点BFS 技巧

题目链接
思路
题意非常简单,最多两个点同时开始烧,最少的花费时间。
暴力枚举一下,我的做法是使用一个标记来记录两个火堆的到达时间以及各自烧了多少。写完之后看了题解。发现有更简单的做法就是不考虑哪个火堆烧的,只记录是否被烧到以及烧到该点的最短时间。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include<queue>
#include <cstring>
using namespace std;

const int inf = 0x7ffffff;

char mp[12][12];
int vis[12][12];
int dir[4][2] = {0,1,0,-1,1,0,-1,0};
int ans;
int n,m;
int total;

struct node {
    int x,y,s;
    node( int _x,int _y,int _s ) {
        x = _x;
        y = _y;
        s = _s;
    }
};

void bfs( int x1,int y1,int x2,int y2 )
{
    memset( vis,0,sizeof vis );
    vis[x1][y1] = vis[x2][y2] = 1 ;
    int cnt = (x1==x2&&y1==y2)?1:2;
    if ( cnt==total ) {
        ans = 0 ;
        return ;
    }
    int cnt1 = 1,cnt2 = 1 ;
    queue<node> que;
    que.push(node(x1,y1,0));
    que.push(node(x2,y2,0));
    while ( !que.empty() ) {
        int t1 = 0 , t2 = 0 ;
        while ( cnt1-- ) {
            node t = que.front();
            que.pop();
            for ( int i=0; i<4; i++) {
                int tx = t.x+dir[i][0];
                int ty = t.y+dir[i][1];
                if ( tx>=0&&ty>=0 && tx<n && ty<m && mp[tx][ty]=='#' && vis[tx][ty]==0 ) {
                    ++cnt;
                    if ( cnt==total ) {
                        ans = min(ans,t.s+1);
                    }
                    ++t1;
                    vis[tx][ty] = 1;
                    que.push(node(tx,ty,t.s+1));
                }
            }
        }

        while ( cnt2-- ) {
            node t = que.front();
            que.pop();
            for ( int i=0; i<4; i++) {
                int tx = t.x+dir[i][0];
                int ty = t.y+dir[i][1];
                if ( tx>=0&&ty>=0 && tx<n && ty<m && mp[tx][ty]=='#' && vis[tx][ty]==0 ) {
                    ++cnt;
                    if ( cnt==total ) {
                        ans = min(ans,t.s+1);
                    }
                    ++t2;
                    vis[tx][ty] = 1;
                    que.push(node(tx,ty,t.s+1));
                }
            }
        }
        cnt1 = t1;
        cnt2 = t2;
    }
}
int main()
{
    int T;
    cin>>T;
    for ( int t=1; t<=T ; t++ ) {
        scanf("%d%d",&n,&m);
        total = 0 ;
        for ( int i=0;i<n;i++ ) {
            for ( int j=0; j<m; j++ ) {
                scanf(" %c",&mp[i][j]);
                if ( mp[i][j]=='#' )
                    ++total;
            }
        }

        ans = inf;
        for ( int i=0; i<n; i++ ) {
            for ( int j=0; j<m; j++ ) {
                if ( mp[i][j]=='#' ) {
                    for ( int k=0; k<n; k++ ) {
                        for ( int l=0; l<m; l++ ) {
                            if ( mp[k][l]=='#' ) {
                                bfs( i,j,k,l );
                            }
                        }
                    }
                }

            }
        }
        if ( ans==inf )
            ans = -1 ;
        printf("Case %d: %d\n" , t , ans);
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值