LeetCode-803 打砖块 (并查集)

题面(传送门)

思路

  • 求与最顶端相接的连通快,那么可以加一个虚点代表“顶端”,把最顶端的点与其相连。
  • 连通块,想到可以用并查集来维护。
  • 按顺序依次删除点,并求此时与虚点处于同一连通快的点的个数。删点操作不好维护并查集,可是加点好操作,于是考虑逆向求。
  • 先把要删掉的点全删掉得到一个最终状况,再按逆序一个个点加回去,维护并查集并处理答案即可。
  • 注:为了方便,我将二维坐标压缩到一个 int 里面了(数据比较小,本质上复杂度啥的没有变)
  • 复杂度应该是 O(mn),都用在枚举图上的点去了。

代码

//https://leetcode-cn.com/problems/bricks-falling-when-hit/
#include <vector>
#include <cstdio>
#include <iostream>
using namespace std;

class Solution {
public:
	#define MAX 200
	#define ID(x,y) ((x-1)*(MAX+1)+y)	//x,y:1~MAX
	inline bool OK(int x,int y){return ((x)>0 && (x)<=n && (y)>0 && (y)<=m);}
	
	int n,m,q,num,tmp;
	int f[ID(MAX,MAX)]={0},sum[ID(MAX,MAX)]={0};
	int graph[ID(MAX,MAX)]={0};
	int Fx[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
	
	int Fa(int x) {
		if (f[x]==x) {
			return x;
		}
		f[x]=Fa(f[x]);
		sum[f[x]]+=sum[x];
		sum[x]=0;
		return f[x];
	}
	
	void merge(int x, int y) {	//x->y
		int rx=Fa(x),ry=Fa(y);
		if (rx==ry) {
			return ;
		}
		f[rx]=ry;
		sum[ry]+=sum[rx];
		sum[rx]=0;
	}
	
    vector<int> hitBricks(vector<vector<int>>& grid, vector<vector<int>>& hits) {    	
        n=grid.size();
        m=grid[0].size();
        q=hits.size();
        num=0;
        vector<int> ret(q);
        
        for (int i=1,id; i<=n; i++) {
        	for (int j=1; j<=m; j++) {
        		id=ID(i,j);
        		f[id]=id;
        		num+=sum[id]=graph[id]=grid[i-1][j-1];
			}
		}
        
        for (auto I: hits) if (grid[I[0]][I[1]]) {
        	graph[ID(I[0]+1,I[1]+1)]=0;
		}
		
  		for (int i=1,id; i<=n; i++) {
			for (int j=1; j<=m; j++) {
				id=ID(i,j);
				if (graph[id]) {
					if (j>1 && graph[ID(i,j-1)])
						merge(id,ID(i,j-1));
					if (i>1 && graph[ID(i-1,j)])
						merge(id,ID(i-1,j));
					if (i==1)
						merge(id,0);
				}
			}
		}
		
		tmp=sum[Fa(0)];
		
		for (int Q=q-1,i,j,id,xx,yy; Q>=0; Q--) {
			i=hits[Q][0]+1;
			j=hits[Q][1]+1;
			id=ID(i,j);
			
			if (sum[id]){
				graph[id]=1;
				for (int fx=0; fx<4; fx++) {
					if (OK(xx=i+Fx[fx][0],yy=j+Fx[fx][1]) && graph[ID(xx,yy)]){
						merge(id,ID(xx,yy));
					}
				}
				if (i==1) {
					merge(id,0);
				}
			}
			ret[Q]=sum[Fa(0)]-tmp-(Fa(id)==Fa(0));
			tmp=sum[Fa(0)];
		}
		
		return ret;
    }
};

int main()
{
	vector<vector<int>> grid={{1,0,1},{1,1,1}};
	vector<vector<int>> hits={{0,0},{0,2},{1,1}};
	Solution S;
	vector<int> ans;
	ans=S.hitBricks(grid,hits);
	for (int i=0; i<ans.size(); i++) {
		cout <<ans[i] <<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值