以DFS和BFS为主的复习。
-
DFS
题目1链接:http://hihocoder.com/problemset/problem/1310?sid=1348820
题意:和蓝桥杯省赛那题有点像。岛屿问题。题目求的是有多少个岛屿,多少个面积不同的岛屿,多少个形状不同的岛屿。
注意:这里形状相同指的是一个岛屿可以由另一个平移得到(不能旋转)
题解:
求有多少不同岛屿==求连同块的数量,求有多少面积不同的岛屿顺手用map统计一下就行了
关键在于求有多少形状不同的岛屿。我们对于一个点(x,y),可以把它哈希成x*(n-1)+y,当然这是从x,y都从1开始的情况。然后把一个联通块的哈希值加入vector,排个序。
对比两个联通块形状是否相同,就是判断两个vector的size是否相同,以及每个元素对应差值是否相同。
bool isok(int i,int j)
{
if(e[i].size()!=e[j].size())
return false;
int temp = e[i][0]-e[j][0];
for(int k=1;k<e[i].size();k++)
{
if(temp!=e[i][k]-e[j][k])
return false;
}
return true;
}
思考点:如何求有多少个不同的。这时候的求法应该是,每加入一个元素,看其与之前的元素是否都不同,如果存在相同的,那么flag就是false,反之为true,结果+1.
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 55;
#define eps 1e-8
#define INIT(x) memset(x,0,sizeof(x))
typedef long long ll;
inline void read(int &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
inline void print(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
int n,m,ans1,ans2,ans3,tot;
char s[maxn][maxn];
bool vis[maxn][maxn];
int dir[4][2] = {1,0,-1,0,0,1,0,-1};
map<int,int> mp;
vector<int> e[maxn*10];
void dfs(int x,int y,int &tot)
{
tot++;
vis[x][y] = 1;
e[ans1].push_back(x*m+y+1);
for(int i=0;i<4;i++)
{
int newx = x+dir[i][0];
int newy = y+dir[i][1];
if(!vis[newx][newy]&&newx>=0&&newy>=0&&newx<n&&newy<m&&s[newx][newy]=='#')
{
dfs(newx,newy,tot);
}
}
}
bool isok(int i,int j)
{
if(e[i].size()!=e[j].size())
return false;
int temp = e[i][0]-e[j][0];
for(int k=1;k<e[i].size();k++)
{
if(temp!=e[i][k]-e[j][k])
return false;
}
return true;
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
scanf("%s",s[i]);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(s[i][j]=='#'&&vis[i][j]==0)
{
tot = 0;
ans1++;
dfs(i,j,tot);
sort(e[ans1].begin(),e[ans1].end());
mp[tot]++;
}
}
}
for(int i=1;i<=ans1;i++)
{
bool flag = 0;
for(int j=1;j<i;j++)
{
if(isok(i,j))
flag = 1;
}
if(!flag)
ans3++;
}
cout<<ans1<<" "<<mp.size()<<" "<<ans3<<endl;
return 0;
}
-
BFS
题目链接:http://hihocoder.com/problemset/problem/1092?sid=1348945
题意:有两个人从同一点出发,要找两个相邻的座位。问加起来的最短路。
题解:可以现在地图上面找用多少个位置符合条件,每遇到两个相邻的座位,就把他们分别加入bfs求最短路,如果两个最短路之和<ans,那么就更新结果。
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 105;
#define eps 1e-8
#define INIT(x) memset(x,0,sizeof(x))
typedef long long ll;
int n,m,sx,sy,ans=inf,temp_ans=inf;
char s[maxn][maxn];
int dir[4][2] = {1,0,0,1,0,-1,-1,0};
bool vis[maxn][maxn];
struct node{
int x,y,step;
};
void bfs(int x,int y)
{
INIT(vis);
node a;
a.x = sx;
a.y = sy;
a.step = 0;
queue<node> q;
while(!q.empty())
q.pop();
q.push(a);
while(!q.empty())
{
node pre = q.front();
// cout<<pre.x<<" "<<pre.y<<endl;
q.pop();
for(int i=0;i<4;i++)
{
int newx = pre.x + dir[i][0];
int newy = pre.y + dir[i][1];
if(!vis[newx][newy]&&newx>=0&&newx<n&&y>=0&&newy<m&&s[newx][newy]!='P'&&s[newx][newy]!='#')
{
if(s[newx][newy]=='S'&&(newx!=x||newy!=y))
continue;
vis[newx][newy] = 1;
node cnt;
cnt.x = newx;
cnt.y = newy;
cnt.step = pre.step+1;
if(newx==x&&newy==y) {
temp_ans = min(temp_ans,cnt.step);
return;
}
q.push(cnt);
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
scanf("%s",s[i]);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(s[i][j]=='H')
{
sx = i;
sy = j;
}
// cout<<sx<<" "<<sy<<endl;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(s[i][j]=='S')
{
bool flag = 0;
int newx,newy;
for(int k=0;k<4;k++)
{
newx = i+dir[k][0];
newy = j+dir[k][1];
if(s[newx][newy]=='S')
{
flag = 1;
break;
}
}
if(flag)
{
temp_ans = inf;
bfs(i,j);
int ans1 = temp_ans;
temp_ans = inf;
bfs(newx,newy);
int ans2 = temp_ans;
ans = min(ans,ans1+ans2);
}
}
}
}
if(ans>=inf)
{
cout<<"Hi and Ho will not have lunch."<<endl;
return 0;
}
cout<<ans<<endl;
return 0;
}
注意点:最大只能设为0x3f3f3f3f,而不是2^31-1,因为可能ans1+ans2溢出,导致ans变小