Hdu 6341 Problem.J Let Sudoku Rotate(dfs+剪枝)
阿新 • • 發佈:2018-11-11
題意就是給你一個已經解完的數獨,但是他的某幾塊被逆時針旋轉過幾次,問你最小的旋轉次數。
當時比賽的時候,因為被題面嚇到了,以為是難題,就沒有仔細思考,現在看看,就是一道搜尋題,用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;
}
}