kmjp's blog

競技プログラミング参加記です

yukicoder : No.2412 YOU Grow Bigger!

こちらも割とすんなり。
https://yukicoder.me/problems/no/2412

問題

2次元グリッドが与えられる。
一部マスは通過不可である。

ここで、3*3マスのサイズの駒を、左上から右下マスに移動したい。
駒は8近傍に1マス分移動できる。ただし移動先に通過不可マスがあってはならない。

通過不可マスを増やし、駒を左上から右下に移動不可にしたい。
最小何マス追加すればよいか。

解法

2マス移動不可マスを追加すれば、駒は左上マスから移動できなくなる。
そこで、解を判定するには

  • 1マスも通過不可マスを追加しないケース
  • 1マスだけ通過不可マスを追加するケース

を考えればよい、後者は全マス総当たりしても間に合う。

int H,W;
string S[2424];
int ok[2424][2424];
int D[2424][2424];

int hoge() {
	int y,x,dy,dx;
	FOR(y,H-2) FOR(x,W-2) {
		D[y][x]=0;
		ok[y][x]=1;
		for(dy=y;dy<=y+2;dy++) for(dx=x;dx<=x+2;dx++) if(S[dy][dx]=='#') ok[y][x]=0;
	}
	D[0][0]=1;
	queue<int> Q;
	Q.push(0);
	while(Q.size()) {
		int cy=Q.front()/10000;
		int cx=Q.front()%10000;
		Q.pop();
		if(cy==H-3&&cx==W-3) return 0;
		for(y=cy-1;y<=cy+1;y++) for(x=cx-1;x<=cx+1;x++) {
			if(x<0||x>W-3||y<0||y>H-3) continue;
			if(ok[y][x]==0) continue;
			if(D[y][x]==1) continue;
			D[y][x]=1;
			Q.push(y*10000+x);
		}
	}
	return 1;
	
}

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>H>>W;
	FOR(y,H) cin>>S[y];
	
	if(hoge()) {
		cout<<0<<endl;
		return;
	}
	
	FOR(y,H) FOR(x,W) if(S[y][x]=='.') {
		if(y<=2&&x<=2) continue;
		if(y>=H-3&&x>=W-3) continue;
		S[y][x]='#';
		if(hoge()) {
			cout<<1<<endl;
			return;
		}
		S[y][x]='.';
	}
	cout<<2<<endl;
	
}

まとめ

考察すると最大値が小さくなるの、Codeforcesでしばしば現れるイメージ。