3808: Neerc2012 Labyrinth of the Minotaur

題目大意:給你一個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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章