ZOJ-2411 link link look


提交到ZOJ,WA了N次,终于修成正果^_^,排在第三位。 

我的思路是这样的:

从S和T分别如图扩展,如果扩展过程相遇,直接返回可以消去,否则还得像箭头那样扫描,如果同时扫过黄色和蓝色,返回可以消去。

当然,这些过程中还有许多细节,请参阅源代码。

补充一点,这个代码改一改就可以做成连连看的游戏,不过少了判断死锁的模块和生成新游戏的模块。

/*
 * ZOJ Problem Set - 2411 Link Link Look
 * Analysis: BFS
 * Author: mike-w
 */

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<string.h>
#define INPUT "input.txt"
#define SIZE 100

int grid[SIZE+2][SIZE+2];
bool mark[SIZE+2][SIZE+2];

/*
 * 我的一个思路是BFS,可惜我写不出来==!
 * 我的另一个思路是*&&^&$#$——一个说不清楚的办法...
 * 具体实现是从起点和终点开始向上下左右四个方向延伸标记
 * 然后再用一条直线扫描
 */
int click(int x1,int y1,int x2,int y2,int maxx,int maxy)
{
	if(x1==x2&&y1==y2)
		return 0;
	if(grid[x1][y1]!=grid[x2][y2])				/* 方块颜色不同 */
		return 0;
	if(!grid[x1][y1])							/* 点击在空白处 */
		return 0;

	int rec1,rec2,rec3,rec4,i,j,v;
	memset(mark,0,sizeof(mark));
	mark[x1][y1]=mark[x2][y2]=1;
	v=grid[x1][y1];
	grid[x1][y1]=grid[x2][y2]=0;
	
	/* 从 (x1,y1) 开始探索 */
	for(i=1;x1+i<=maxx+1&&!grid[x1+i][y1];i++)	/* 向下探索 */
		if(mark[x1+i][y1])
			return 2;
		else mark[x1+i][y1]=1;
	rec1=x1+i-1;
	for(i=1;x1-i>=0&&!grid[x1-i][y1];i++)		/* 向上探索 */
		if(mark[x1-i][y1])
			return 2;
		else mark[x1-i][y1]=1;
	rec2=x1-i+1;
	for(i=1;y1+i<=maxy+1&&!grid[x1][y1+i];i++)	/* 向右探索 */
		if(mark[x1][y1+i])
			return 2;
		else mark[x1][y1+i]=1;
	rec3=y1+i-1;
	for(i=1;y1-i>=0&&!grid[x1][y1-i];i++)		/* 向左探索 */
		if(mark[x1][y1-i])
			return 2;
		else mark[x1][y1-i]=1;
	rec4=y1-i+1;
	
	/* 从终点 (x2,y2) 开始探索 */
	for(i=1;x2+i<=maxx+1&&!grid[x2+i][y2];i++)	/* 向下探索 */
		if(mark[x2+i][y2])
			return 2;
		else mark[x2+i][y2]=1;
	for(i=1;x2-i>=0&&!grid[x2-i][y2];i++)		/* 向上探索 */
		if(mark[x2-i][y2])
			return 2;
		else mark[x2-i][y2]=1;
	for(i=1;y2+i<=maxy+1&&!grid[x2][y2+i];i++)	/* 向右探索 */
		if(mark[x2][y2+i])
			return 2;
		else mark[x2][y2+i]=1;
	for(i=1;y2-i>=0&&!grid[x2][y2-i];i++)		/* 向左探索 */
		if(mark[x2][y2-i])
			return 2;
		else mark[x2][y2-i]=1;

	/* 开始“神奇地”扫描 */
	for(i=rec2;i<=rec1;i++)						/* 水平扫描 */
	{
		if(i==x1)
			continue;
		for(j=1;y1+j<=maxy+1&&!grid[i][y1+j];j++)
			if(mark[i][y1+j])					/*  这时已经不需要再标记了 */
				return 2;
		for(j=1;y1-j>=0&&!grid[i][y1-j];j++)
			if(mark[i][y1-j])
				return 2;
	}
	for(i=rec4;i<=rec3;i++)						/* 垂直扫描 */
	{
		if(i==y1)
			continue;
		for(j=1;x1+j<=maxx+1&&!grid[x1+j][i];j++)
			if(mark[x1+j][i])
				return 2;
		for(j=1;x1-j>=0&&!grid[x1-j][i];j++)	/* 其实这两个for只有一个做有用功 */
			if(mark[x1-j][i])
				return 2;
	}
	grid[x1][y1]=grid[x2][y2]=v;				/* 恢复grid的值 */
	return 0;									/* 消掉0个 */
}

int main(void)
{
	int nclick,n,m;
	int x1,x2,y1,y2,i,j;
	int dis=0;

/*	freopen(INPUT,"r",stdin);	*/

	while(scanf("%d%d",&n,&m)!=EOF&&m&&n)
	{
		dis=0;
		memset(grid,0,sizeof(grid));
		
		for(i=1;i<=n;i++)
			for(j=1;j<=m;j++)
				scanf("%d",grid[i]+j);
	
		scanf("%d",&nclick);
		while(nclick--)
		{
			scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
			dis+=click(x1,y1,x2,y2,n,m);	/* click() 返回消去的方块数 */
		}
		printf("%d\n",dis);
	}
	return 0;
}


 下面是第二个版本,做了一小点优化,不过还是20ms

/*
 * ZOJ Problem Set - 2411 Link Link Look
 * Analysis: BFS
 * Author: mike-w
 */

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<string.h>
#define INPUT "input.txt"
#define SIZE 100

int grid[SIZE+2][SIZE+2];
bool mark[SIZE+2][SIZE+2];

/*
 * 我的一个思路是BFS,可惜我写不出来==!
 * 我的另一个思路是*&&^&$#$——一个说不清楚的办法...
 * 具体实现是从起点和终点开始向上下左右四个方向延伸标记
 * 然后再用一条直线扫描
 */
int click(int x1,int y1,int x2,int y2,int maxx,int maxy)
{
	if(x1==x2&&y1==y2)
		return 0;
	if(grid[x1][y1]!=grid[x2][y2])				/* 方块颜色不同 */
		return 0;
	if(!grid[x1][y1])							/* 点击在空白处 */
		return 0;

	int rec1,rec2,rec3,rec4,i,j,v;
	memset(mark,0,sizeof(mark));
	mark[x1][y1]=mark[x2][y2]=1;
	v=grid[x1][y1];
	grid[x1][y1]=grid[x2][y2]=0;
	
	/* 从 (x1,y1) 开始探索 */
	for(i=1;x1+i<=maxx+1&&!grid[x1+i][y1];i++)	/* 向下探索 */
		if(mark[x1+i][y1])
			return 2;
		else mark[x1+i][y1]=1;
	rec1=x1+i-1;
	for(i=1;x1-i>=0&&!grid[x1-i][y1];i++)		/* 向上探索 */
		if(mark[x1-i][y1])
			return 2;
		else mark[x1-i][y1]=1;
	rec2=x1-i+1;
	for(i=1;y1+i<=maxy+1&&!grid[x1][y1+i];i++)	/* 向右探索 */
		if(mark[x1][y1+i])
			return 2;
		else mark[x1][y1+i]=1;
	rec3=y1+i-1;
	for(i=1;y1-i>=0&&!grid[x1][y1-i];i++)		/* 向左探索 */
		if(mark[x1][y1-i])
			return 2;
		else mark[x1][y1-i]=1;
	rec4=y1-i+1;
	
	/* 从终点 (x2,y2) 开始探索 */
	for(i=1;x2+i<=maxx+1&&!grid[x2+i][y2];i++)	/* 向下探索 */
		if(mark[x2+i][y2])
			return 2;
		else mark[x2+i][y2]=1;
	for(i=1;x2-i>=0&&!grid[x2-i][y2];i++)		/* 向上探索 */
		if(mark[x2-i][y2])
			return 2;
		else mark[x2-i][y2]=1;
	for(i=1;y2+i<=maxy+1&&!grid[x2][y2+i];i++)	/* 向右探索 */
		if(mark[x2][y2+i])
			return 2;
		else mark[x2][y2+i]=1;
	for(i=1;y2-i>=0&&!grid[x2][y2-i];i++)		/* 向左探索 */
		if(mark[x2][y2-i])
			return 2;
		else mark[x2][y2-i]=1;

	/* 开始“神奇地”扫描 */
	for(i=rec2;i<=rec1;i++)						/* 水平扫描 */
	{
		if(i==x1||y1==y2)
			continue;
		if(y2>y1)
		{
			for(j=1;y1+j<=maxy+1&&!grid[i][y1+j];j++)
				if(mark[i][y1+j])					/*  这时已经不需要再标记了 */
					return 2;
		}
		else
		{
			for(j=1;y1-j>=0&&!grid[i][y1-j];j++)
				if(mark[i][y1-j])
					return 2;
		}
	}
	for(i=rec4;i<=rec3;i++)						/* 垂直扫描 */
	{
		if(i==y1||x1==x2)
			continue;
		if(x2>x1)
		{
			for(j=1;x1+j<=maxx+1&&!grid[x1+j][i];j++)
				if(mark[x1+j][i])
					return 2;
		}
		else
		{
			for(j=1;x1-j>=0&&!grid[x1-j][i];j++)
				if(mark[x1-j][i])
					return 2;
		}
	}
	grid[x1][y1]=grid[x2][y2]=v;				/* 恢复grid的值 */
	return 0;									/* 消掉0个 */
}

int main(void)
{
	int nclick,n,m;
	int x1,x2,y1,y2,i,j;
	int dis=0;

/*	freopen(INPUT,"r",stdin);	*/

	while(scanf("%d%d",&n,&m)!=EOF&&m&&n)
	{
		dis=0;
		memset(grid,0,sizeof(grid));
		
		for(i=1;i<=n;i++)
			for(j=1;j<=m;j++)
				scanf("%d",grid[i]+j);
	
		scanf("%d",&nclick);
		while(nclick--)
		{
			scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
			dis+=click(x1,y1,x2,y2,n,m);	/* click() 返回消去的方块数 */
		}
		printf("%d\n",dis);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值