赛克oj 1540 开心消消乐(并查集、模拟、回溯)
赛氪OJ-专注于算法竞赛的在线评测系统 (saikr.com)
题目描述
近来,小明的班上风靡着一款名为“开心消消乐”的游戏,为了成为大家眼中的超人,小明开始疯狂研究这款游戏的玩法。
游戏的场景是一个𝑛×𝑚n×m的正方形矩阵,其中有着4种不同形状的方块,玩家要做的就是尽可能多的消除掉其中的方块。
在游戏中,各个方块和上下左右四个方向的相邻位置上形状相同的方块共同构成了一个又一个连通块,玩家选中一个位置后,若该位置所在连通块的方块总数不小于3,那么就可以消除掉这一连通块,得到分数。需要注意的是,游戏存在着重力机制,在机制作用下,每次消除后腾空的方块会下落。
显然,由于重力机制的影响,消除顺序会影响到游戏的最终得分,现在给定游戏矩阵,若简单记每个方块为1分,请试着找出最大的得分。
输入
输入格式:
- 第一行输入两个数n、m,表示矩阵大小。
- 之后n行,每行m个数,表示方块矩阵。每个数可能为1、2、3、4,分别对应一种形状。
输出
输出格式:
- 输出一行一个数,表示最大得分。
思路
模拟题。用回溯来进行消除顺序的确定,用并查集消除某一块,主要是注意细节。
1 #define IO std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) 2 #define bug(x) cout<<#x<<" is "<<x<<endl 3 #include <bits/stdc++.h> 4 #define iter ::iterator 5 using namespace std; 6 typedef long long ll; 7 typedef pair<int,int>P; 8 #define pb push_back 9 #define mk make_pair 10 #define se second 11 #define fi first 12 #define rs o*2+1 13 #define ls o*2 14 15 int n,m,ans; 16 17 int a[10][10]; 18 19 int fa[50]; 20 21 int find(int x){ 22 return fa[x]==x?x:fa[x]=find(fa[x]); 23 } 24 int check(int x,int y){ 25 if(x<1||x>n||y<1||y>m||!a[x][y])return 0; 26 return 1; 27 } 28 29 int dx[4]={0,0,1,-1}; 30 int dy[4]={1,-1,0,0}; 31 32 int flag[10][10]; 33 34 int cnt[50]; 35 36 void gao(int h){ 37 int res=0; 38 //printf("h=%d\n",h); 39 for(int i=1;i<=n;i++){ 40 for(int j=1;j<=m;j++){ 41 if(!a[i][j])res++; 42 //printf("%d ",a[i][j]); 43 } 44 //printf("\n"); 45 } 46 //printf("\n"); 47 ans=max(ans,res); 48 if(h==9){ 49 return; 50 } 51 for(int i=1;i<=n*m;i++)fa[i]=i,cnt[i]=0; 52 53 for(int i=1;i<=n;i++){ 54 for(int j=1;j<=m;j++){ 55 for(int k=0;k<4;k++){ 56 if(!a[i][j])continue; 57 58 int x=i+dx[k]; 59 int y=j+dy[k]; 60 if(check(x,y)&&a[x][y]==a[i][j]){ 61 int nid=(x-1)*m+y; 62 int id=(i-1)*m+j; 63 int fa1=find(id); 64 int fa2=find(nid); 65 //bug(fa1); 66 fa[fa1]=fa2; 67 } 68 } 69 } 70 } 71 for(int i=1;i<=n*m;i++){ 72 int x=find(i); 73 cnt[x]++; 74 } 75 76 int tot[50]; 77 int ma[50]; 78 int b[10][10]; 79 80 for(int i=1;i<=n*m;i++)tot[i]=cnt[i],ma[i]=fa[i]; 81 82 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)b[i][j]=a[i][j]; 83 for(int f=1;f<=n*m;f++){ 84 if(cnt[f]>=3){ 85 //bug(f); 86 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)flag[i][j]=0; 87 for(int k=1;k<=n*m;k++){ 88 if(find(k)!=f)continue; 89 int x,y; 90 if(k%m==0){ 91 x=k/m; 92 y=m; 93 } 94 else{ 95 x=k/m+1; 96 y=k%m; 97 } 98 //printf("%d %d\n",x,y); 99 flag[x][y]=1; 100 } 101 for(int i=1;i<=m;i++){ 102 103 for(int j=n;j>=1;j--){ 104 int t=0; 105 for(int k=j+1;k<=n;k++){ 106 if(flag[k][i])t++; 107 } 108 a[j+t][i]=a[j][i]; 109 } 110 int mx=0; 111 for(int j=1;j<=n;j++)if(flag[j][i])mx++; 112 for(int k=1;k<=mx;k++){ 113 a[k][i]=0; 114 } 115 } 116 //printf("%d \n",h); 117 gao(h+1); 118 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)flag[i][j]=0,a[i][j]=b[i][j]; 119 for(int i=1;i<=n*m;i++)cnt[i]=tot[i],fa[i]=ma[i]; 120 121 122 } 123 } 124 125 } 126 127 int main(){ 128 129 IO; 130 cin>>n>>m; 131 for(int i=1;i<=n;i++){ 132 for(int j=1;j<=m;j++){ 133 cin>>a[i][j]; 134 } 135 } 136 137 138 gao(0); 139 140 cout<<ans<<endl; 141 142 143 144 145 } 146 /* 147 3 5 148 4 4 4 1 4 149 4 2 2 2 1 150 3 3 3 1 4 151 152 */