FZU2150(双起点bfs->多起点)
题目大意:
给出一个height*width的图,'#'表示草坪,'.'表示空地,然后可以选择在任意的两个草坪格子点火,火每 1 s会向周围四个格子扩散,问选择那两个点使得燃烧所有的草坪花费时间最小?
大致思路:
重点是和单起点bfs差不多,唯一不同的就是在刚开始入队的时候将两个起点都入队。可以说是对两个不同根节点的树进行搜索吧(两棵树根节点可相同可不同,枝叶可交叉可不交叉),主要思路就是这个样子喽,剩下的细节就看个人怎么处理了。同样也可以类比到多起点的搜索。而且如果单纯的暴力枚举的话会计算大量的重复所以可以增加一个dat数组讲草的位置保存下来,进行一些优化。(本人对图的建坐标方式可能恰好相反,见谅!)。
这是我的代码运行结果(前一次写的TLE了(小声
#include <bits/stdc++.h>
using namespace std;
int x,y;
const int MAX = 15;
int dir[][2] = {{-1,0},{0,-1},{1,0},{0,1}};
char vis[MAX][MAX],cur[MAX][MAX];
int path[MAX][MAX]; //这个二维数组记录对草对两个起点的最大距离(也就是火烧到此处的时间
struct node{
int x,y;
node(int xx=0,int yy=0):
x(xx),y(yy){}
};
#define check(dx,dy) (0<=dx && dx<x && 0<=dy && dy<y)
vector dat; //这个保存草的位置
int bfs(node fir,node sec)
{
memset(path,0,sizeof path);
memcpy(cur,vis,sizeof vis);
queue que;
que.push(fir),que.push(sec); //两个结点同时入队
cur[fir.y][fir.x] = '.';cur[sec.y][sec.x] = '.';
while (!que.empty())
{
node tmp = que.front(); que.pop();
for (int i=0;i<4;i++)
{
int dx = tmp.x+dir[i][0],dy = tmp.y+dir[i][1];
if (check(dx,dy) && '#'==cur[dy][dx])
{
que.push(node(dx,dy));
path[dy][dx] = path[tmp.y][tmp.x] + 1;
cur[dy][dx] = '.';
}
}
}
int res = -0x3f3f3f3f;
for (int i=0;i<y;i++)
for (int j=0;j<x;j++)
{
if (path[i][j]>res)
res = path[i][j];
if ('#'==cur[i][j])
return -1; //如果发现草没有烧完,就返回-1,否则返回时间
}
return res;
}
int main()
{
int t;
while (cin >> t){
int count = 0;
while (t--){
cin >> y >> x;
dat.clear();
for (int i=0;i<y;i++)
{
scanf("%s",vis[i]);
for (int j=0;j<x;j++)
if ('#'==vis[i][j])
dat.push_back(node(j,i));
}
int ans = 0x3f3f3f3f; //枚举
for (int i=0;i<dat.size();i++)
for (int j=i;j<dat.size();j++)
{
int tmp = bfs(dat[i],dat[j]);
if (-1==tmp)
continue;
if (tmp<ans)
ans = tmp;
}
if (0x3f3f3f3f==ans)
ans = -1;
cout << "Case " << ++count << ": " << ans << endl;
}
}
return 0;
}
