题意:
题意:给出一个m*n的图,‘#’表示草坪,‘ . ’表示空地,然后可以选择在任意的两个草坪格子点火,火每 1 s会向周围四个格子扩散,问选择那两个点使得燃烧所有的草坪花费时间最小?
思路: 暴力搜索
首先判断有几个连通块,如果超过2个,则无解。否则,枚举两个的初始位置,bfs后取最小值。
小优化:把在一个连通块的点放一块,这样如果有2个连通块,这两个初始点必然分布在这两个不同的连通块里,省去了无用的枚举。
// 650ms
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <algorithm>
#define fi first
#define se second
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 15;
int move[4][2] = {{0,1}, {1,0}, {0,-1}, {-1,0}};
char G[maxn][maxn];
int vis[maxn][maxn];
int d[maxn][maxn];
int n,m,ans;
// 求联通快
void dfs(int x, int y){
vis[x][y] = 1;
for(int i = 0; i < 4; ++i){
int x2 = x + move[i][0];
int y2 = y + move[i][1];
if(x2 >= 0&&x2 < n&&y2 >= 0&&y2 < m&&G[x2][y2] == '#'&&!vis[x2][y2]){
dfs(x2, y2);
}
}
}
struct Node{
int x, y, step;
Node(int a = 0, int b = 0, int c = 0):x(a),y(b),step(c){}
};
void bfs(int x1, int y1, int x2, int y2){
memset(vis, 0, sizeof(vis));
memset(d, INF, sizeof(d));
vis[x1][y1] = vis[x2][y2] = 1;
queue<Node> Q;
Q.push(Node(x1,y1,1));
if(x1 != x2 || y1 != y2) Q.push(Node(x2,y2,1));
Node next;
while(!Q.empty()){
Node t = Q.front(); Q.pop();
d[t.x][t.y] = min(d[t.x][t.y], t.step);
for(int i = 0; i < 4; ++i){
next.x = t.x + move[i][0];
next.y = t.y + move[i][1];
if(next.x >= 0&&next.x < n&&next.y >= 0&&next.y < m&&G[next.x][next.y] == '#'&&vis[next.x][next.y] == 0){
vis[next.x][next.y] = 1;
next.step = t.step + 1;
Q.push(next);
}
}
}
}
void find_ans(){
int t = 0;
for(int i = 0; i < n; ++i){
for(int j = 0; j < m; ++j){
if(G[i][j] == '#')
t = max(t, d[i][j]-1);
}
}
ans = min(ans, t);
}
int main()
{
freopen("in.txt","r",stdin);
int T; scanf("%d",&T);
int kase = 1;
while(T--){
scanf("%d %d",&n,&m);
printf("Case %d: ",kase++);
for(int i = 0; i < n; ++i){
scanf("%s",G[i]);
}
memset(vis, 0, sizeof(vis));
int cnt = 0; // 联通快
bool flag = true;
for(int i = 0; i < n; ++i){
for(int j = 0; j < m; ++j){
if(G[i][j] == '#'&&!vis[i][j]){
++cnt;
if(cnt > 2) { flag = false; break; }
dfs(i, j);
}
}
if(!flag) break;
}
//printf("blocks %d ",cnt);
if(!flag) printf("-1\n");
else{
ans = INF;
for(int x1 = 0; x1 < n; ++x1)
for(int y1 = 0; y1 < m; ++y1)
for(int x2 = 0; x2 < n; ++x2)
for(int y2 = 0; y2 < m; ++y2){
if(G[x1][y1] == '#'&&G[x2][y2] == '#'){
bfs(x1,y1,x2,y2);
//printf("%d %d -> %d %d, = %d \n",x1,y1,x2,y2,t);
//finalans = min(finalans, t);
find_ans();
}
}
printf("%d\n", ans);
}
}
return 0;
}
加小优化后,(数据量小,优势不明显):
//500ms
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <algorithm>
#define fi first
#define se second
#define pii pair<int,int>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 15;
int move[4][2] = {{0,1}, {1,0}, {0,-1}, {-1,0}};
char G[maxn][maxn];
int vis[maxn][maxn];
int d[maxn][maxn];
vector<pii> blocks[3];
int n,m,ans;
// 求联通快
void dfs(int x, int y, int c){
vis[x][y] = 1;
blocks[c].push_back( make_pair(x,y) );
for(int i = 0; i < 4; ++i){
int x2 = x + move[i][0];
int y2 = y + move[i][1];
if(x2 >= 0&&x2 < n&&y2 >= 0&&y2 < m&&G[x2][y2] == '#'&&!vis[x2][y2]){
dfs(x2, y2, c);
}
}
}
struct Node{
int x, y, step;
Node(int a = 0, int b = 0, int c = 0):x(a),y(b),step(c){}
};
int bfs(int x1, int y1, int x2, int y2){
memset(vis, 0, sizeof(vis));
memset(d, INF, sizeof(d));
vis[x1][y1] = vis[x2][y2] = 1;
queue<Node> Q;
Q.push(Node(x1,y1,1));
if(x1 != x2 || y1 != y2) Q.push(Node(x2,y2,1));
Node next;
int maxd = 0;
while(!Q.empty()){
Node t = Q.front(); Q.pop();
d[t.x][t.y] = min(d[t.x][t.y], t.step);
for(int i = 0; i < 4; ++i){
next.x = t.x + move[i][0];
next.y = t.y + move[i][1];
if(next.x >= 0&&next.x < n&&next.y >= 0&&next.y < m&&G[next.x][next.y] == '#'&&vis[next.x][next.y] == 0){
vis[next.x][next.y] = 1;
next.step = t.step + 1;
maxd = max(maxd, next.step-1);
Q.push(next);
}
}
}
return maxd;
}
int main()
{
freopen("in.txt","r",stdin);
int T; scanf("%d",&T);
int kase = 1;
while(T--){
scanf("%d %d",&n,&m);
printf("Case %d: ",kase++);
for(int i = 0; i < n; ++i){
scanf("%s",G[i]);
}
memset(vis, 0, sizeof(vis));
blocks[1].clear(); blocks[2].clear();
int cnt = 0; // 联通快
bool flag = true;
for(int i = 0; i < n; ++i){
for(int j = 0; j < m; ++j){
if(G[i][j] == '#'&&!vis[i][j]){
++cnt;
if(cnt > 2) { flag = false; break; }
dfs(i, j, cnt);
}
}
if(!flag) break;
}
//printf("blocks %d ",cnt);
if(!flag) printf("-1\n");
else{
int s1,s2; //连通块编号
if(cnt == 1){
s1 = s2 = 1;
}
else{
s1 = 1; s2 = 2;
}
ans = INF;
for(vector<pii>::iterator it = blocks[s1].begin(); it != blocks[s1].end(); ++it){
for(vector<pii>::iterator it2 = blocks[s2].begin(); it2 != blocks[s2].end(); ++it2){
int x1 = it->fi, y1 = it->se;
int x2 = it2->fi, y2 = it2->se;
int t = bfs(x1, y1, x2, y2);
ans = min(ans, t);
}
}
printf("%d\n",ans);
}
}
return 0;
}