Flood-it![POJ4007][CH2912]

欢迎大家访问我的老师的OJ———caioj.cn

题面描述

传送门

思路

这道题关键在于怎么确定状态。

一开始想的时候满脑子都是想法

结果想了一会,发现貌似每一个格子都在被遍历到。

那开始的状态就没什么要求了。

那我们就从 ( 1 , 1 ) (1,1) (1,1)左上角开始吧。

a [ 1 ] [ 1 ] a[1][1] a[1][1]的颜色标记为 1 1 1.

方向就不用细讲了。

const int dx[4]={0,0,-1,1};
const int dy[4]={-1,1,0,0};

遍历时,碰到不同颜色的格子标记为 2 2 2.

碰到相同颜色的格子标记为 1 1 1,且将状态拓展到那个格子上。

本次递归停下来了,随便找到一个被标记为 2 2 2的格子

继续递归。

但是这样,貌似好像还会超时。

先来个迭代加深吧,限制一下深度,使它不要那么放飞自我

再来个估值函数

是这样设计的

经过慎重的思考,我们可以发现

我们至少要将非标记为1的各种颜色的格子给踩一下,才能使所有格子同一颜色

所以

int gj()
{
	int cnt=0;
	bool w[6];memset(w,false,sizeof(w));
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(!w[a[i][j]]&&v[i][j]!=1)
			{
				cnt++;w[a[i][j]]=1;
			}
	return cnt;
}

AC code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
using namespace std;
const int N=10;
const int dx[4]={0,0,-1,1};
const int dy[4]={-1,1,0,0};
int v[N][N],a[N][N],n,dep;
bool pd(int x,int y){return x>0&&x<=n&&y>0&&y<=n;}
void dfs(int x,int y,int z)
{
	v[x][y]=1;
	for(int i=0;i<4;i++)
	{
		int nx=x+dx[i],ny=y+dy[i];
		if(!pd(nx,ny))continue;
		if(v[nx][ny]==1)continue;
		v[nx][ny]=2;if(a[nx][ny]==z)dfs(nx,ny,z);
	}
}
int gj()
{
	int cnt=0;
	bool w[6];memset(w,false,sizeof(w));
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(!w[a[i][j]]&&v[i][j]!=1)
			{
				cnt++;w[a[i][j]]=1;
			}
	return cnt;
}
bool dfs0(int now)
{
	int cnt=gj();
	if(!cnt)return 1;
	if(now+cnt>dep)return 0;
	int w[N][N];memcpy(w,v,sizeof(v));
	for(int i=0;i<6;i++)
	{
		bool flag=0;
		for(int x=1;x<=n;x++)
			for(int y=1;y<=n;y++)
				if(v[x][y]==2&&a[x][y]==i)
				{
					flag=1;dfs(x,y,a[x][y]);
				}
		if(flag&&dfs0(now+1))return 1;
		memcpy(v,w,sizeof(w));
	}
	return 0;
}
int main()
{
	while(scanf("%d",&n)&&n)
	{
		if(!n)break;memset(v,0,sizeof(v));
		for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&a[i][j]);
		dfs(1,1,a[1][1]);
		dep=0;
		while(!dfs0(0))dep++;
		printf("%d\n",dep);
	}
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值