1 条题解
-
1
【题目大意】给定一个由若干个不同种类的俄罗斯方块构成的的网格图,求有多少种不同种类的俄罗斯方块,相同种类的俄罗斯方块定义为仅通过平移可以重合。
【考纲知识点】图的遍历,集合
【解题思路】可以立刻想到这是一个 Flood Fill(洪水填充)DFS 算法,但问题也随之而来,如何判断两种图形是不是同一图形?也就是去重问题,说到去重,大家应该会想到
set
,不仅去重还排序,那我们又如何用set
去存储一个图形呢?很简单,直接把这个图形所有节点扔进去,并让这些节点保持有序,这样,下一次遇见这种图形,set
直接就去掉了,最后的答案就是set.size()
。剩下的就是一些模板了。参考程序
#include<bits/stdc++.h> #define ll long long #define MAXN 1000 using namespace std; ll n,m; ll a[MAXN][MAXN];//原数组 ll vis[MAXN][MAXN];//标记访问 ll movex[4]={1,0,-1,0}; ll movey[4]={0,1,0,-1}; //位移数组 vector<pair<ll,ll>>g;//图形 set<vector<pair<ll,ll>>>s;//去重 set void dfs(ll x,ll y){//Blood Fill模板 vis[x][y]=1;//标记起点 g.push_back({x,y});//加入图形 for(ll i=0;i<4;i++){ ll nownx=x+movex[i],nowny=y+movey[i];//加上位移量 if(nownx>=1 and nownx<=n and nowny>=1 and nowny<=m and vis[nownx][nowny]==0 and a[nownx][nowny]==a[x][y])dfs(nownx, nowny); //判断是否越界,是否访问过,是否是同一种颜色 } } void work(){ ll minx=INT_MAX,miny=INT_MAX; for(ll i=0;i<g.size();i++) minx=min(minx,g[i].first),miny=min(miny,g[i].second); for(ll i=0;i<g.size();i++) g[i].first-=minx,g[i].second-=miny; sort(g.begin(),g.end());//让图形变得有序才能去重 s.insert(g);//直接扔进去 } void init(){ cin>>n>>m; for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++) cin>>a[i][j]; } void ma(){ for(ll i=1;i<=n;i++)//遍历每一个位置 for(ll j=1;j<=m;j++){ if(vis[i][j]==0){//如果没有被访问过就以此节点为起点,发动 flood fill g.clear();//记得清空 dfs(i,j);//发动搜索 work();//记录 } } } int main() { init(); ma(); cout<<s.size();//s里面有多少个元素即为答案 return 0; }
- 1
信息
- ID
- 653
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 9
- 标签
- 递交数
- 8
- 已通过
- 7
- 上传者