拯救oibh总部

9 篇文章 0 订阅
5 篇文章 0 订阅

题目背景

oibh 总部突然被水淹没了!现在需要你的救援……

题目描述

oibh 被突来的洪水淹没了,还好 oibh 总部有在某些重要的地方起一些围墙。用 * 号表示,而一个四面被围墙围住的区域洪水是进不去的。

oibh 总部内部也有许多重要区域,每个重要区域在图中用一个 0 表示。

现在给出 oibh 的围墙建设图,问有多少个没被洪水淹到的重要区域。

输入格式

第一行为两个正整数 x,yx,y。

接下来 xx 行,每行 yy 个整数,由 * 和 0 组成,表示 oibh 总部的建设图。

输出格式

输出没被水淹没的 oibh 总部的 0 的数量。

输入输出样例

输入 #1复制

4 5
00000
00*00
0*0*0
00*00

输出 #1复制

1

输入 #2复制

5 5
*****
*0*0*
**0**
*0*0*
*****

输出 #2复制

5

说明/提示

对于 100\%100% 的数据,1 \le x,y \le 5001≤x,y≤500。

1.dp

我用 \large dp_{i,j}dpi,j​ 表示矩阵中ii行jj列的状态,其中:

如果 \large dp_{i,j}=1dpi,j​=1 就表示矩阵中ii行jj列是墙;

如果 \large dp_{i,j}=0dpi,j​=0 就表示矩阵中ii行jj列是当前未被淹没的空地;

相反,如果 \large dp_{i,j}=2dpi,j​=2 就表示被淹没的空地。

然后,我们便可以把水淹没空地的过程抽象成被淹没的地将'被淹没'的状态转移给旁边空地的模型。

再说具体点,就是如果当前的 \large dp_{i,j}dpi,j​ 是2,就把它旁边的00也变成22,这就是深搜或宽搜的过程。

但是,我们可以对此过程进行一个优化,仔细想想,把刚才过程倒过来,就是:

如果当前的 \large dp_{i,j}dpi,j​ 是00且它四周有被淹没的地,或者说如果\large dp_{i,j}=0dpi,j​=0且dp_{i-1,j}dpi−1,j​或dp_{i+1,j}dpi+1,j​或dp_{i,j-1}dpi,j−1​或dp_{i,j+1}dpi,j+1​中任意一个是22,则 \large dp_{i,j}dpi,j​ 应变为22.

那我们现在就可以把代码写出来了。

我还是放一下代码,供大家参考。

3.Code

#include<bits/stdc++.h>
using namespace std;
int dp[505][505],n,m,ans,last;
char ch;
int main(void){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			std::cin>>ch;
			if(ch=='*')dp[i][j]=1;
			//输入 
		}
	}
	for(int i=1;i<=n;i++){
		if(dp[i][1]==0)ans++,dp[i][1]=2;
		if(dp[i][m]==0)ans++,dp[i][m]=2;
		//初始化 
	}
	for(int i=1;i<=m;i++){
		if(dp[1][i]==0)ans++,dp[1][i]=2;
		if(dp[n][i]==0)ans++,dp[n][i]=2;
		//同上 
	}
	while(1){last=ans;ans=0;//一遍遍转移状态 
		for(register int i=1;i<=n;i++){
			for(register int j=1;j<=m;j++){
				if(dp[i][j]==0&&(dp[i-1][j]==2||dp[i+1][j]==2||dp[i][j-1]==2||dp[i][j+1]==2)){
					dp[i][j]=2;
					//状态转移 
				}
			}
		}
		for(register int i=1;i<=n;i++){
			for(register int j=1;j<=m;j++){
				if(dp[i][j]==0)ans++;
				//统计答案 
			}
		}
		if(last==ans){
			cout<<ans;
			return 0;
			//输出并退出 
		}
	}
	return 0;
}

2.DFS

首先我们要想清楚我们搜索的是什么

我们搜索的应该是会被淹到的部分,一旦找到会被淹到的部分,就把它变成‘*’。

所以这题就很像找

联通块!!!

所以,我们的代码应该是:

#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
//#pragma GCC optimize(3)
//sort(st.begin(),st.end());
using namespace std;
int xx[10]={0,0,-1,1};
int yy[10]={1,-1,0,0};
int n,m,gs;
char ch[510][510];
void dfs(int x,int y)
{
	if(x<1||y<1||x>n||y>m||ch[x][y]=='*')return;//边界
	ch[x][y]='*';//标记
	for(int i=0; i<4; i++)
		dfs(x+xx[i],y+yy[i]);//深度优先搜索
}
int main()
{
	cin>>n>>m;
	for(int i=1; i<=n; i++)
	    for(int j=1; j<=m; j++)
	        cin>>ch[i][j];
	dfs(1,1);
	for(int i=1; i<=n; i++)
	    for(int j=1; j<=m; j++)
	    {
	    	if(ch[i][j]=='0')
	    	{
	    		gs++;
			}
		}
	cout<<gs;
    return 0;
}

可当你信心满满的提交时,你就会收到luogu测评器给你的拥抱!!

想知道为什么吗?

看看我下面出的这个数据:

5 5
0*000
*0000
00000
00000
00000

你会发现他给出的答案是22。?????

那是因为我们刚搜到第一个0后就搜不下去了。

所以我想到了一个新办法:

多搜一圈!!!

#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
//#pragma GCC optimize(3)
//sort(st.begin(),st.end());
using namespace std;
int xx[10]={0,0,-1,1};
int yy[10]={1,-1,0,0};
int n,m,gs;
char ch[510][510];
void dfs(int x,int y)
{
	if(x<0||y<0||x>n+1||y>m+1||ch[x][y]=='*')return;
	ch[x][y]='*';
	for(int i=0; i<4; i++)
		dfs(x+xx[i],y+yy[i]);
}
int main()
{
	cin>>n>>m;
	for(int i=1; i<=n; i++)
	    for(int j=1; j<=m; j++)
	        cin>>ch[i][j];
	dfs(0,0);//多搜一圈
	for(int i=1; i<=n; i++)
	    for(int j=1; j<=m; j++)
	    {
	    	if(ch[i][j]=='0')
	    	{
	    		gs++;
			}
		}
	cout<<gs;
    return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值