1 条题解

  • 1
    @ 2024-6-6 16:47:19

    【题目大意】给定一个由若干个不同种类的俄罗斯方块构成的nmn*m的网格图,求有多少种不同种类的俄罗斯方块,相同种类的俄罗斯方块定义为仅通过平移可以重合。

    【考纲知识点】图的遍历,集合

    【解题思路】可以立刻想到这是一个 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

    [GESP202403 七级] 俄罗斯方块

    信息

    ID
    653
    时间
    1000ms
    内存
    512MiB
    难度
    9
    标签
    递交数
    8
    已通过
    7
    上传者