トピック
問題の説明
次のように、特定の海域のNxNピクセル写真があります。「。」は海を意味し、「#」は陸地を意味します。
…
。##…
。##
……##。
…####。
…###。
…
その中で、「上、下、左、右」の4方向につながった土地が島を形成しています。たとえば、上の写真には2つの島があります。
地球温暖化によって引き起こされる海面上昇のために、科学者たちは、島の端のピクセルが今後数十年で海水に沈むだろうと予測しています。具体的には、陸のピクセルが海に隣接している場合(上下、左、右の4つの隣接するピクセルに海があります)、水没します。
たとえば、上の写真の海域は、将来的には次のようになります。
……………… #
…………
_
_ _ _
数えてください:科学者の予測によると、写真に写っている島の数は完全に水没します。
入力形式
最初の行には整数Nが含まれています。(1 <= N <= 1000)
次のN行とN列は、海域の写真を表しています。
写真は、行1、列1、行N、および列Nのピクセルがすべて海であることを保証します。
出力形式
回答を表す整数。
サンプル入力
7
…
。##…
。##
………##。
…####。
…###。
…
サンプル出力
1
分析する
#とそれに接続されているすべての#が島を形成します。ここでの接続とは、上、下、左、右を指します。次に、変更前の島の数を計算し、次に水没した島の数を計算してから、変更後の島、そして減算が答えです。島の数を計算するには、dfsを使用して島のすべての土地をマークする必要があり、変更にはシミュレーションと判断が必要です。
コードセクション
1.ループスルー
マップ全体をトラバースし、#が表示された場合はカウントに1を追加し、dfsはそれに接続されているすべての#をマークします
cin>>n;
vector<vector<char> > _map(n,vector<char>(n)); //地图
vector<vector<bool> > vis(n,vector<bool>(n,0)); //标记
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>_map[i][j];
int oldcnt=0;
for(int i=0;i<n;i++) //计算变化前岛屿数量
{
for(int j=0;j<n;j++)
{
if(_map[i][j]=='#'&&vis[i][j]==0)
{
oldcnt++;
dfs(i,j,_map,vis);
}
}
}
2.dfs
最初にdfsの機能を理解し、現在の位置から接続されているすべての#をマークします。これは、上下左右の4つの方向です。簡単にするために、変化を表す方向座標として2つの1次元配列を開きます。方向を変えてから、4つの方向を横断します。各方向に加えて、次の位置を歩くことができるかどうかを判断し、毎回現在の位置をすでに歩いたものとしてマークします。
const int dx[4]={
0,0,1,-1}; //方向
const int dy[4]={
1,-1,0,0};
void dfs(int x,int y,vector<vector<char> > &_map,vector<vector<bool> > &vis)
{
//出口
vis[x][y]=1;
//现在能做的事情
for(int i=0;i<4;i++)
{
if(x+dx[i]>=0&&x+dx[i]<n&&y+dy[i]>=0&&y+dy[i]<n&&
vis[x+dx[i]][y+dy[i]]==0&&
(_map[x+dx[i]][y+dy[i]]=='#'||_map[x+dx[i]][y+dy[i]]=='!'))
{
dfs(x+dx[i],y+dy[i],_map,vis);
}
}
}
3.マップ全体をシミュレートして判断します
以前は、現在の場所が水没する場合は。に変更したとシミュレートして判断していましたが、後でこれが不可能であることがわかりました。最後に、マップ内のすべてのグリッドが。に変更され、次に沈めるグリッド!
bool check(int x,int y,vector<vector<char> > &_map) //判断该岛屿是否会被淹没
{
for(int i=0;i<4;i++)
{
if(x+dx[i]>=0&&x+dx[i]<n&&y+dy[i]>=0&&y+dy[i]<n)
{
if(_map[x+dx[i]][y+dy[i]]=='.')
return true;
}
}
return false;
}
for(int i=0;i<n;i++) //改变地图标记被淹没的陆地
{
for(int j=0;j<n;j++)
{
if(_map[i][j]=='#'&&check(i,j,_map))
{
_map[i][j]='!';
}
}
}
4.変更後の島の数を決定します
以前のように島の数を直接計算すると、一部の島が変更された後、直接計算すると2つの島になるため、機能しません。ここでの質問の意味はあまり明確ではないため、 #判断するとき、しかし!これらの土地は以前は島だったので、場所もマークされて判断されます
vector<vector<bool> > vis2(n,vector<bool>(n,0)); //标记
int nowcnt=0;
for(int i=0;i<n;i++) //计算变化后岛屿数量
{
for(int j=0;j<n;j++)
{
if(_map[i][j]=='#'&&vis2[i][j]==0)
{
nowcnt++;
dfs(i,j,_map,vis2);
}
}
}
完全なコード
#include <bits/stdc++.h>
using namespace std;
int n;
const int dx[4]={
0,0,1,-1}; //方向
const int dy[4]={
1,-1,0,0};
void dfs(int x,int y,vector<vector<char> > &_map,vector<vector<bool> > &vis)
{
//出口
vis[x][y]=1;
//现在能做的事情
for(int i=0;i<4;i++)
{
if(x+dx[i]>=0&&x+dx[i]<n&&y+dy[i]>=0&&y+dy[i]<n&&
vis[x+dx[i]][y+dy[i]]==0&&
(_map[x+dx[i]][y+dy[i]]=='#'||_map[x+dx[i]][y+dy[i]]=='!'))
{
dfs(x+dx[i],y+dy[i],_map,vis);
}
}
}
bool check(int x,int y,vector<vector<char> > &_map) //判断该岛屿是否会被淹没
{
for(int i=0;i<4;i++)
{
if(x+dx[i]>=0&&x+dx[i]<n&&y+dy[i]>=0&&y+dy[i]<n)
{
if(_map[x+dx[i]][y+dy[i]]=='.')
return true;
}
}
return false;
}
int main (void)
{
cin>>n;
vector<vector<char> > _map(n,vector<char>(n)); //地图
vector<vector<bool> > vis(n,vector<bool>(n,0)); //标记
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>_map[i][j];
int oldcnt=0;
for(int i=0;i<n;i++) //计算变化前岛屿数量
{
for(int j=0;j<n;j++)
{
if(_map[i][j]=='#'&&vis[i][j]==0)
{
oldcnt++;
dfs(i,j,_map,vis);
}
}
}
for(int i=0;i<n;i++) //改变地图标记被淹没的陆地
{
for(int j=0;j<n;j++)
{
if(_map[i][j]=='#'&&check(i,j,_map))
{
_map[i][j]='!';
}
}
}
/*
for(int i=0;i<n;i++) //输出改变后的地图
{
for(int j=0;j<n;j++)
{
cout<<_map[i][j];
}
cout<<endl;
}
*/
vector<vector<bool> > vis2(n,vector<bool>(n,0)); //标记
int nowcnt=0;
for(int i=0;i<n;i++) //计算变化后岛屿数量
{
for(int j=0;j<n;j++)
{
if(_map[i][j]=='#'&&vis2[i][j]==0)
{
nowcnt++;
dfs(i,j,_map,vis2);
}
}
}
cout<<oldcnt-nowcnt;
return 0;
}
要約する
この質問にはたくさんのコードがありますが、繰り返される場所がたくさんあり、アイデアは難しくありません。これは基本的なdfだけですが、注意が必要な詳細がいくつかあります。