方格填数-搜索练习题

1160: 方格填数

时间限制: 1 Sec 内存限制: 128 MB
提交: 5 解决: 3
[提交][状态][讨论版]

题目描述

如上面的10个格子,填入0~9的数字,不能重复(原先已经填了一部分数字),要求:连续的两个数字不能相邻(左右,上下,对角都算相邻)。例如:数字0和1不能放在一起。
问:一共有多少种可能的填数方案?

输入

输入多组测试数据。
每组测试数据有三行,第一行三个整数,第二行四个整数,第三行三个整数,之间用空格隔开,分别代表每个空格所填的数,如果原先没有数,则填-1。
输入数据保证不重复数字,不保证连续数字不相邻。

输出

每组测试数据输出一行。
输出表示方案数目的整数。

样例输入

-1 -1 -1
-1 -1 -1 -1
-1 -1 -1
0 1 -1
-1 -1 -1 -1
-1 -1 -1
1 3 5
-1 -1 -1 -1
-1 -1 -1

样例输出

1580
0
8

**模块话思想在复杂问题中作用明显
代码长,好多地方写的效率很低,也懒得再改了,刚好能过就行

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int map[3][4];// 存储 
int NEXT[8][2]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};// 用于判断八个方向 
bool num[10];
int count;
bool isright;//判断输入的数据是否正确 
bool check(int x,int y,int n)//检查八个方向是否有重复 
{
	int i,tx,ty;
	for(i=0;i<8;i++)
	{
		tx = x+NEXT[i][0];
		ty = y+NEXT[i][1];
		if(tx>=0&&tx<3 && ty>=0&&ty<4)
		{
			if(map[tx][ty]!=-5 && (map[tx][ty] == n+1 || map[tx][ty] == n-1))//如果相差为 1 则返回false 
				return false;
			else 
				continue;
		}
	}
	return true;
}

bool Write()//读入函数 
{
	int i;
	memset(num,0,sizeof(num));//读入前清空标记 
	for(i=1;i<4;i++)//读入第一行,从第二个数字开始的 
	{
		if(scanf("%d",&map[0][i])!=EOF)
		{
			if(map[0][i]==-1)//这里把-1变成-5是应为 0 和 -1 也是相邻的, 
				map[0][i]=-5;
			else
				num[map[0][i]] = true;//如果读入数据,就把数字标记 
		}
		else 
			return false;
	}
	for(i=0;i<4;i++)//读入第二行 
	{
		scanf("%d",&map[1][i]);	
		if(map[1][i]==-1)  //同理如上 
				map[1][i]=-5;
		else
				num[map[1][i]] = true;
	}
		
	for(i=0;i<3;i++)
	{
		scanf("%d",&map[2][i]);
		if(map[2][i]==-1)  //同理如上
				map[2][i]=-5;
		else
				num[map[2][i]] = true;
	}
		
	return true;	
}

void dfs(int x)//搜索 
{
	int r,c,i;
	if(x==11)//出口 
	{
		count++;
		return;
	}
	r = x/4;//将点转换为坐标,思路来自八皇后 
	c = x%4;
	if(map[r][c]==-5)//如果==-5 表示我们标记为 空(未填数字) 
	{
		for(i=0;i<=9;i++)
		{
			if(num[i]==false && check(r,c,i)==true)//1,数字i未被使用,2,(r,c)的八个方向与i的值比较 
			{
				num[i] = true;//标记 
				map[r][c] = i;
				dfs(x+1);
				num[i] = false;//去除标记 
				map[r][c] = -5;//!!!一定要把这个位置给复原(-5表示未填数字),我就在这个小问题上卡了进一小时,调试半天, 
			}
		}
	}else
		dfs(x+1);//如果当前位置有数字了,就直接跳过 
}
void check2()//这个check函数用于判断用户输入的结果是否有相邻的值 
{
	int i,r,c;
	for(i=1;i<=11;i++)//模拟搜索,从头看到位, 
	{
		r=i/4;
		c=i%4;
		if(map[r][c]!=-5)
		{
			if(check(r,c,map[r][c])==false)//如果不满足 
			{
				isright = false;//改变我们定义的全局标记 
				return;
			}
			else 
				continue;
		}
			
	}
}
int main()
{
	while(Write()==true)
	{
		map[0][0] = map[2][3] = -5;//把两个角落的值给初始化一样,避免意外(默认初始值为0,就有可能和 0 1 ,相邻) 
		isright = true;
		check2();//检查用户输入 
		if(isright==true)//如果检查正确 
		{	
		count = 0;
		dfs(1);
		cout<<count<<endl;
		}else//不正确直接输出0就好 
			cout<<"0"<<endl;	
	}
	return 0;
}


下面是纯代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int map[3][4];
int next[8][2]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
bool num[10];
int count;
bool isright;
bool check(int x,int y,int n)
{
	int i,tx,ty;
	for(i=0;i<8;i++)
	{
		tx = x+next[i][0];
		ty = y+next[i][1];
		if(tx>=0&&tx<3 && ty>=0&&ty<4)
		{
			if(map[tx][ty]!=-5 && (map[tx][ty] == n+1 || map[tx][ty] == n-1))
				return false;
			else 
				continue;
		}
	}
	return true;
}

bool Write()
{
	int i;
	memset(num,0,sizeof(num));
	for(i=1;i<4;i++)
	{
		if(scanf("%d",&map[0][i])!=EOF)
		{
			if(map[0][i]==-1)
				map[0][i]=-5;
			else
				num[map[0][i]] = true;
		}
		else 
			return false;
	}
	for(i=0;i<4;i++)
	{
		scanf("%d",&map[1][i]);	
		if(map[1][i]==-1)
				map[1][i]=-5;
		else
				num[map[1][i]] = true;
	}
		
	for(i=0;i<3;i++)
	{
		scanf("%d",&map[2][i]);
		if(map[2][i]==-1)
				map[2][i]=-5;
		else
				num[map[2][i]] = true;
	}
		
	return true;	
}

void dfs(int x)
{
	int r,c,i;
	if(x==11)
	{
		count++;
		return;
	}
	r = x/4;
	c = x%4;
	if(map[r][c]==-5)
	{
		for(i=0;i<=9;i++)
		{
			if(num[i]==false && check(r,c,i)==true)
			{
				num[i] = true;
				map[r][c] = i;
				dfs(x+1);
				map[r][c] = -5;
				num[i] = false;
			}
		}
	}else
		dfs(x+1);
}
void check2()
{
	int i,r,c;
	for(i=1;i<=11;i++)
	{
		r=i/4;
		c=i%4;
		if(map[r][c]!=-5)
		{
			if(check(r,c,map[r][c])==false)
			{
				isright = false;
				return;
			}
			else 
				continue;
		}
			
	}
}
int main()
{
	while(Write()==true)
	{
		map[0][0] = map[2][3] = -5;
		
		isright = true;
		check2();
		if(isright==true)
		{	
		count = 0;
		dfs(1);
		cout<<count<<endl;
		}else
			cout<<"0"<<endl;	
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值