1. 程式人生 > >hdu6341 /// 模擬 DFS+剪枝

hdu6341 /// 模擬 DFS+剪枝

sum dfs sed amp for long long lose \n print

題目大意:

將16行16列的矩陣分成四行四列共16塊

矩陣的初始狀態每行及每列都不會出現重復的元素

給定一個已旋轉過某些塊的矩陣 判斷其是由初始狀態最少經過幾次旋轉得到的

DFS枚舉16個塊的旋轉方式

DFS過程中直接進行旋轉 一旦發現旋轉結果與之前枚舉的塊的旋轉結果相悖就剪枝

這個剪枝已經足夠AC 也不妨在加一條當前旋轉次數比之前得到的可能答案大就剪枝

技術分享圖片
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long
#define mem(i,j) memset(i,j,sizeof(i))
const
int N=1e5+5; const int MOD=1e9+7; int G[20][20], g[20][20]; int R[20][20], C[20][20]; int ans; #define w(i) (i-1)*4 #define wG(i,j,I,J) G[w(i)+I][w(j)+J] int get(int r,int c,int x,int y,int k) { if(k==1) return wG(r,c,4-y+1,x); else if(k==2) return wG(r,c,4-x+1,4-y+1); else if(k==3) return wG(r,c,y,4
-x+1); else return wG(r,c,x,y); } // 得到在r,c的塊內x,y位置在第k種旋轉之後的新數值 bool Rotate(int i,int j,int k) { bool OK=1; for(int I=1;I<=4;I++) for(int J=1;J<=4;J++) { int x=w(i)+I, y=w(j)+J; g[x][y]=get(i,j,I,J,k); int r=++R[x][g[x][y]]; int
c=++C[y][g[x][y]]; if(r>1 || c>1) OK=0; // 這種旋轉與之前其他塊的旋轉沖突 // 繼續發展下去得到的一定是錯誤的 } return OK; } // 旋轉i,j塊 方式為第k種 void reRotate(int i,int j) { for(int I=1;I<=4;I++) for(int J=1;J<=4;J++) { int x=w(i)+I, y=w(j)+J; --R[x][g[x][y]]; --C[y][g[x][y]]; g[x][y]=G[x][y]; } } // 將i,j塊的旋轉取消 void dfs(int x,int y,int sum) { if(sum>ans) return; if(x==5) { ans=min(ans,sum); return; } // 四行四列16個塊 到第五行說明已枚舉了所有塊的旋轉 for(int i=0;i<=3;i++) { if(Rotate(x,y,i)==0) { reRotate(x,y); continue; } // 若發現這種旋轉方式會沖突就跳過 if(y==4) dfs(x+1,1,sum+i); else dfs(x,y+1,sum+i); reRotate(x,y); } } // 搜索枚舉16個塊的旋轉方式 int main() { int t; scanf("%d",&t); while(t--) { for(int i=1;i<=16;i++) { char s[20]; scanf("%s",s); for(int j=0;j<16;j++) { if(s[j]>=0 && s[j]<=9) G[i][j+1]=s[j]-0; else G[i][j+1]=s[j]-A+10; } } mem(R,0); mem(C,0); ans=INF; dfs(1,1,0); printf("%d\n",ans); } return 0; }
View Code

hdu6341 /// 模擬 DFS+剪枝