POJ 1027 The Same Game

题意为每次选取图中最大的同色联通块(>=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;
	}
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值