1. 程式人生 > >Hdu 6341 Problem.J Let Sudoku Rotate(dfs+剪枝)

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; } }