Hdu 6341 Problem.J Let Sudoku Rotate(dfs+剪枝)

题意就是给你一个已经解完的数独,但是他的某几块被逆时针旋转过几次,问你最小的旋转次数。
当时比赛的时候,因为被题面吓到了,以为是难题,就没有仔细思考,现在看看,就是一道搜索题,用bfs和dfs都可以过。
一开始想着如果用bfs的话,可能还要存下每旋转一次的状态,会显得很繁琐,就没有选择bfs,用了dfs。
自己写了一个dfs,可能是因为当时有点困,写起来小错误很多,写完debug了很久。虽然出了答案,但样例都会超时,然后想着可能是剪枝没剪好,就加了各种各样的剪枝,交上去还是T了。没办法,去网上学习一下大佬的做法,然后自己重新敲了一遍,因为之前已经写过一遍了,这次就很顺,写完稍微debug一下就出样例了。交上去就过了。680ms
同时,我也发现我原先那个代码的问题了,我旋转矩阵的方法太繁琐了,估计只要换一种旋转方法就可以过了。
(PS:听说有大佬可以剪到15ms,但是没找到,真的是震惊了。)

#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn=20;
int arr[maxn][maxn];
int fl[maxn]={0};
int T;
int Min;
bool pd(int num)
{
	for(int i=1;i<=num;i++)
	{
		memset(fl,0,sizeof fl);
		for(int j=1;j<=16;j++)
		{
			if(fl[arr[j][i]]==0)
				fl[arr[j][i]]=1;
			else return false;
		}
	}
	for(int i=1;i<=16;i++)
	{
		memset(fl,0,sizeof fl);
		for(int j=1;j<=num;j++)
		{
			if(fl[arr[i][j]]==0)
				fl[arr[i][j]]=1;
			else return false;
		}
	}
	return true;
}
void xz(int num,int num1)
{
	int arr1[5][5]={0};
	int a=num1;
	int b=num;
	for(int i=1,a=num1;i<=4;i++,a++)
	{
		for(int j=1,b=num;j<=4;j++,b++)
		{
			arr1[i][j]=arr[a][b];
		}
	}
	for(int i=1,a=num1;i<=4;i++)
	{
		for(int j=1,b=num;j<=4;j++)
		{
			arr[5-j+a-1][b+i-1]=arr1[i][j];
		}
	} 
}
void dfs(int num,int val)
{
	if(val>Min)return;
	if(num==17)
	{
		Min=min(Min,val);
		return;
	}
	for(int i=1;i<=4;i++,xz(num,1))
	{
		for(int j=1;j<=4;j++,xz(num,5))
		{
			for(int m=1;m<=4;m++,xz(num,9))
			{
				for(int n=1;n<=4;n++,xz(num,13))
				{
					if(pd(num+3))
					{
						dfs(num+4,val+i+j+m+n-4);
					}
				}
			}
		}
	}
}
int main()
{
	cin>>T;
	while(T--)
	{
		Min=1000;
		memset(arr,-1,sizeof arr);
		for(int i=1;i<=16;i++)
		{
			char ch[maxn];
			scanf("%s",ch+1);
			for(int j=1;j<=16;j++)
			{
				if(ch[j]>='0'&&ch[j]<='9')
				{
					arr[j][i]=ch[j]-'0';
				}
				else
				{
					arr[j][i]=ch[j]-'A'+10;
				}
			}
		}
		dfs(1,0);
		cout<<Min<<endl;
	}
}

猜你喜欢

转载自blog.csdn.net/qq_41564817/article/details/82322998
今日推荐