现在的位置: 首页 > 综合 > 正文

3808: Neerc2012 Labyrinth of the Minotaur

2017年10月16日 ⁄ 综合 ⁄ 共 2252字 ⁄ 字号 评论关闭

题目大意:给你一个n*m的格子,有些格子有障碍,要你找到一个最小的正方形格子,使得这个正方形没有覆盖障碍且去掉这个正方形后(1,1)与(n,m)就不连通了

n<=1500 m<=1500

这题首先要找到从起点到终点的左手路径与右手路径,左手路径就是用左手一直扶着墙壁走,右手路径就是用右手一直扶着墙壁走。如果一个正方形可以覆盖左右手路径就能让他不连通

首先暴搜每个点,把它作为正方形的右上角点,再找到一个最小的边长,mw,使得这个正方形可以阻断(如果任意的合法的mw都不能使得其阻断,就是最大的合法的边长),

如果这个正方形可以阻断,且这个正方形中没有障碍就可以用mw来更新答案了。

我开始的做法是二分找mw,结果发现慢的飞起,是O(n^2logn)的,后来经过仔细研究终于找到了一种去除log的方法

对于一个点(i,j)它的mw是k,那么(i,j+1)的mw<=k+1,这个是很显然的,因为以(i,j+1)为右上角,边长为k+1的正方形是包含以(i,j)为右上角,边长为k的正方形的

所以我们每次求一个点的mw时,就把上一个点的mw+1,在while mw-1也可以阻断路径时就把mw-1,这样就可以求出mw了,因为mw只加了n^2次,所以复杂度是O(n^2)

#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1511;
const int ax[]={-1,0,1,0},ay[]={0,1,0,-1};
int n,m; char map[maxn][maxn];
void init(){
	scanf("%d%d",&m,&n);
	for (int i=1;i<=n;++i) scanf("%s",map[i]+1);
}
bool vis[maxn][maxn];
inline bool cvis(int x,int y){return x<=n && x>=1 && y<=m && y>=1 && map[x][y]=='.';}
void get(int k,int x,int y,int w){
	while (x!=n || y!=m){
		vis[x][y]=1; int dx,dy,dw;
		dw=(w+k+4)&3,dx=x+ax[dw],dy=y+ay[dw]; if (cvis(dx,dy)) {x=dx,y=dy,w=dw; continue;}
		dw=w,dx=x+ax[dw],dy=y+ay[dw]; if (cvis(dx,dy)) {x=dx,y=dy,w=dw; continue;}
		dw=(w-k+4)&3,dx=x+ax[dw],dy=y+ay[dw]; if (cvis(dx,dy)) {x=dx,y=dy,w=dw; continue;}
		dw=(w+2)&3,dx=x+ax[dw],dy=y+ay[dw]; if (cvis(dx,dy)) {x=dx,y=dy,w=dw; continue;}
	}
}
struct Tmx{
	int a[maxn][maxn];
	void getpxsm(){
		for (int i=1;i<=n;++i) for (int j=1;j<=m;++j)
			a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
	}
	inline int Query(int x1,int y1,int x2,int y2){
		return a[x2][y2]-a[x1][y2]-a[x2][y1]+a[x1][y1];
	}
}mp,lt,rt;
inline bool check(int x,int y,int dx,int dy){
	return (x || y) && (dx!=n || dy!=m) && 
	lt.Query(x,y,dx,dy) && rt.Query(x,y,dx,dy);
}
void work(){
	for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) mp.a[i][j]=map[i][j]=='#';
	mp.getpxsm(); get(-1,1,1,1);
	for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) lt.a[i][j]=vis[i][j]; lt.getpxsm();
	for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) vis[i][j]=0; get(1,1,1,2);
	for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) rt.a[i][j]=vis[i][j]; rt.getpxsm();
	int ans=min(n,m)+1,ax=-1,ay;
	for (int i=1;i<=n;++i){
		int mw=0;
		for (int j=1;j<=m;++j){
			++mw;
			while (mw && (i+mw-1>n || mp.Query(i-1,j-mw,i+mw-1,j))) --mw;
			while (mw>1 && check(i-1,j-mw+1,i+mw-2,j)) --mw;
			if (mw<ans && check(i-1,j-mw,i+mw-1,j)) ans=mw,ax=i,ay=j-mw+1;
		}
	}
	if (ax==-1) puts("Impossible"); else printf("%d %d %d\n",ans,ay,ax);
}
int main(){
	init();
	work();
	return 0;
}

抱歉!评论已关闭.