[Codeforces 1214D]Treasure Island(dfs)


[Codeforces 1214D]Treasure Island(dfs)

題面

給出一個n*m的字符矩陣,'.'表示能通過,'#'表示不能通過。每步可以往下或往右走。問至少把多少個'.'變成'#',才能讓從(1,1)出發不能到達(n,m)

\(n \times m \leq 10^6\)

分析

第一眼還以為是最小割,一看數據范圍感覺會TLE。實際上搜索就可以了。

首先發現答案肯定是0,1,2中的一個(輸出rand()%3),因為最多用2個'#',把(1,1)右側和下方堵住就可以了。

然后注意到若存在一個點滿足所有(1,1)到(n,m)的路徑都經過那個點,那答案就為1.這實際上是一個有向圖求割點的問題,類似HDU3313.

我們只需要dfs一遍,找出任意一條(1,1)到(n,m)的路徑,然后把路徑上的點標記為1。注意若(1,1)不能到(n,m),直接輸出0.第二次dfs保證不經過路徑上的點。如果第二次的時候(1,1)不能到(n,m),那就說明存在割點,答案為1。否則答案為2.

注意到數據范圍\(n \times m \leq 10^6\),沒有給出n,m的范圍,所以要用vector存儲字符矩陣。

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define maxn 1000000
using namespace std;
int n,m;
char in[maxn+5];
vector<char>s[maxn+5];
struct node{
	int x;
	int y;
	node(){
		
	}
	node(int _x,int _y){
		x=_x;
		y=_y;
	}
};
const int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
vector<bool>vis[maxn+5];
vector<bool>mark[maxn+5];
bool dfs(int x,int y){
	if(x>n||y>m) return 0;
	if(x==n&&y==m) return 1;
	if(s[x][y]=='#'||vis[x][y]||mark[x][y]) return 0;
	vis[x][y]=1;
	bool flag=dfs(x+1,y);
	if(!flag) flag=dfs(x,y+1);
        //優先往(x+1,y)走,如果走不通再往(x,y+1)走,這樣就可以避免被堵住的情況,詳見評論區
	if(flag) mark[x][y]=1;
	return flag;
}
int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%s",in+1);
		s[i].resize(m+1);
		for(int j=1;j<=m;j++) s[i][j]=in[j];
		vis[i].resize(m+1);
		mark[i].resize(m+1); 
	}
	bool flag=dfs(1,1);
	if(!flag) printf("0\n");
	else{
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++) vis[i][j]=0;
		}
		mark[1][1]=mark[n][m]=0;
		flag=dfs(1,1);
		if(!flag) printf("1\n");
		else printf("2\n");
	}
		
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM