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