题意为每次选取图中最大的同色联通块(>=2) 进行消除,接着消除之后上面的元素会往下落,如果出现空列,则右边的列会向左移动。输出为第几次,联通块的左下角,联通块的数量,联通块的颜色,得分(联通块的数量-2)的平方。
对于这种大型的模拟题来说,最简单的方法就是分拆问题。我们可以将问题分拆为以下几个方面。
1. 统计联通块数量:每次从左下角开始,DFS解决。
2. 从上往下落:每次n的三次方枚举,从左向右从下往上枚举每一行每一列,对于每一个空格,向上找最近的非空格进行填充。
3.从左向右列转移:也是分拆,第一步统计空列位置,对于每一个空列,向右找最近的非空列,复制元素即可。
这样一个大问题便被分拆成了几个入门者都很容易实现的函数,即可完成任务。
下附AC代码。
#include<iostream>
#include<string.h>
#include<algorithm>
#define maxn 20
using namespace std;
char g[maxn][maxn];
int vis[maxn][maxn];
int n=10,m=15;
int nowx,nowy,nowans,maxnow,sum;
int fx[]={0,1,-1,0,0};
int fy[]={0,0,0,1,-1};
void dfs(int x,int y)
{
if(vis[x][y]) return;
nowans++;
vis[x][y]=1;
for(int i=1;i<=4;i++)
{
int nx=x+fx[i];
int ny=y+fy[i];
if(!vis[nx][ny] && g[nx][ny]==g[x][y] && 1<=nx && nx<=n && 1<=ny && ny<=m)
{
dfs(nx,ny);
}
}
}
void mark(int x,int y)
{
if(g[x][y]==0) return;
int preg=g[x][y];
g[x][y]=0;
for(int i=1;i<=4;i++)
{
int nx=x+fx[i];
int ny=y+fy[i];
if(g[nx][ny]!=0 && g[nx][ny]==preg && 1<=nx && nx<=n && 1<=ny && ny<=m)
{
mark(nx,ny);
}
}
}
void cutshu()
{
for(int j=1;j<=m;j++)
for(int i=n;i>=1;i--)
if(g[i][j]!=0)
{
int trans=i;
for(int k=i+1;k<=n;k++)
{
if(g[k][j]==0) trans=k;
else break;
}
if(trans==i) continue;
else
{
g[trans][j]=g[i][j];
g[i][j]=0;
}
}
}
void cutheng()
{
int temp[maxn];
memset(temp,0,sizeof(temp));
for(int j=1;j<=m;j++)
{
for(int i=n;i>=1;i--)
if(g[i][j]!=0)
{
temp[j]++;
}
}
for(int i=1;i<=m;i++)
{
if(temp[i]!=0)
{
for(int j=1;j<=i-1;j++)
if(temp[j]==0)
{
temp[j]=temp[i];
for(int k=1;k<=n;k++)
{
g[k][j]=g[k][i];
}
for(int k=1;k<=n;k++)
{
g[k][i]=0;;
}
temp[i]=0;
break;
}
}
}
for(int i=1;i<=m;i++)
if(temp[i]==0)
{
m=i;
break;
}
}
int findlef()
{
int res=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(g[i][j]!=0)
res++;
return res;
}
int main()
{
int t;
cin>>t;
int useles=0;
while(t--)
{
m=15,n=10;
useles++;
cout<<"Game "<<useles<<":"<<endl<<endl;
sum=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>g[i][j];
}
int times=0;
while(1)
{
times++;
memset(vis,0,sizeof(vis));
int ans=0;
for(int j=1;j<=m;j++)
for(int i=n;i>=1;i--)
if(!vis[i][j] && g[i][j]!=0)
{
nowans=0;
dfs(i,j);
if(nowans>ans)
{
ans=nowans;
nowx=i;
nowy=j;
}
else if(nowans==ans)
{
if(j<nowy)
{
nowy=j;
nowx=i;
}
else if(nowy==j)
{
if(i>nowx)
{
nowx=i;
nowy=j;
}
}
}
}
if(ans<2)
break;
cout<<"Move"<<" "<<times<<" at ("<<n-nowx+1<<","<<nowy<<"): removed "<<ans<<" balls of color "<<g[nowx][nowy]<<", got "<<(ans-2)*(ans-2)<<" points."<<endl;
sum+=((ans-2)*(ans-2));
mark(nowx,nowy);
cutshu();
cutheng();
}
int lef=findlef();
if(lef==0) sum+=1000;
cout<<"Final score: "<<sum<<", with "<<lef<<" balls remaining."<<endl<<endl;
}
}