zoj 1008 Gnome Tetravex

题目链接

题意 有一些卡片上下左右均有数字,要求将这些卡片拼成正方形,并且相接部分数字相同:

思路:dfs深搜,但要注意如果直接暴力的话,深搜是一个全排列问题,计算量最大是为25!,这个数字是非常大的,但如果对卡片进行分类,即上下左右均相等的卡片分成一类,这样全排列的计算量将大大减小,

这里我测试了两种思路稍有不同的代码,如下:

经测试第二种稍微快一点,应该是是因为跳出的较快,  总的来说对dfs的返回及恢复初始值问题是比较难理解透彻的,稍不注意就超时或者其他各种问题

此外本体还应注意一些换行及空格问题,oj无情啊。。。

#include<iostream>
#include<stdio.h>
using namespace std;
int n,q;
int isqure[25][4];//储存卡片的种类
int icount[25];//储存每种卡片的数量
int itable[25];//存储各位置放置的卡片种类
int dfs(int num)
{
	int i;
	if(num==n*n)//最后一个卡片已经放置完成,返回
		return 1;
	for(i=0;i<q;i++)//检查每一个卡片能否放置
	{
		if(icount[i]==0)//该种类卡片无剩余,搜索下一个
			continue;
		if(num%n!=0)//不是最左边一行,检查与左边连接处数字是否相同
		    if(isqure[itable[num-1]][1]!=isqure[i][3])
		        continue;
		if(num>=n)不是最上面一行,检查与上面连接处数字是否相同
			if(isqure[itable[num-n]][2]!=isqure[i][0])
				continue;
		itable[num]=i;//标记该位置放置的卡片种类
		icount[i]--;//卡片数量减1
		if(dfs(num+1)==1) return 1; //注意理解这里的返回与卡片数量的恢复,
		icount[i]++;
	}
	return 0;
}

int main()
{
	//freopen("in.txt","r",stdin);
	int ans=1;
	while(scanf("%d",&n)!=EOF&&n)
	{
        q=0;//卡片的种类
		int top,right,bottm,left;
		for(int i=0;i<n*n;i++)
		{
			scanf("%d%d%d%d",&top,&right,&bottm,&left);
            int j=0;
			for(j=0;j<q;j++)//检查输入的卡片是否已将存过,若存过,该种类数量加1
			{
				if(isqure[j][0]==top && isqure[j][1]==right && isqure[j][2]==bottm && isqure[j][3]==left)
				{
					icount[j]++;
					break;
				}
			}
			if(j==q)//如果没存过该种卡片,建立新的卡片种类,并使其初始值为1,同时卡片种类q加1
			{
				isqure[j][0]=top;
				isqure[j][1]=right;
				isqure[j][2]=bottm;
				isqure[j][3]=left;
				q++;
				icount[j]=1;
			}
		}
			int flag=dfs(0);
			if(ans-1)
                printf("\n");
			printf("Game %d: ",ans++);
			if(flag)
				printf("Possible\n");
			else 
			    printf("Impossible\n");
            
		
	}
}



#include<iostream>
#include<stdio.h>
using namespace std;
int n,q,flag;
int isqure[25][4];
int icount[25];
int itable[25];
void dfs(int num)
{
	int i;
	if(flag)return;//这里如果没有一个检查过程,本解法将会超时
	if(num==n*n)
	{
		flag=1;
		return ;
	}
		
	for(i=0;i<q;i++)
	{
		if(icount[i]==0)
			continue;
		if(num%n!=0)
		    if(isqure[itable[num-1]][1]!=isqure[i][3])
		        continue;
		if(num>=n)
			if(isqure[itable[num-n]][2]!=isqure[i][0])
				continue;
		itable[num]=i;
		icount[i]--;
		//if(dfs(num+1)==1) return 1;
		dfs(num+1);
		icount[i]++;
	}
	return ;
}

int main()
{
	//freopen("in.txt","r",stdin);
	int ans=1;
	while(scanf("%d",&n)!=EOF&&n)
	{		
        flag=q=0;
		int top,right,bottm,left;
		for(int i=0;i<n*n;i++)
		{
			scanf("%d%d%d%d",&top,&right,&bottm,&left);
            int j=0;
			for(j=0;j<q;j++)
			{
				if(isqure[j][0]==top && isqure[j][1]==right && isqure[j][2]==bottm && isqure[j][3]==left)
				{
					icount[j]++;
					break;
				}
			}
			if(j==q)
			{
				isqure[j][0]=top;
				isqure[j][1]=right;
				isqure[j][2]=bottm;
				isqure[j][3]=left;
				q++;
				icount[j]=1;
			}
		}
		dfs(0);
		if(ans-1)
		    printf("\n");
		printf("Game %d: ",ans++);
		if(flag)
			printf("Possible\n");
		else 
			printf("Impossible\n");
			
		
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值