P1092 [NOIP2004 提高组] 虫食算
考察:dfs+剪枝
思路:
从最后一列开始dfs,用bool 数组记录哪些数字被使用了即可.接下来思考如何剪枝:
- 搜索顺序剪枝: 从大到小枚举,大数字在低位可能性较大.
- 冗余处理:这里是排列型枚举.
- 可行性剪枝:比较关键,需要两个剪枝:高位无进位. 从第1列~第n列检查是否符合实际.
- 最优性剪枝:无
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int N = 30; 6 int n,a[N],b[N]; 7 char s[4][N]; 8 bool st[N]; 9 int Getid(int i,int j) 10 { 11 return s[i][j]-'A'; 12 } 13 bool check() 14 { 15 int s1 = Getid(1,1),s2 = Getid(2,1),s3; 16 if(a[s1]!=-1&&a[s2]!=-1) 17 { 18 int K = a[s1]+a[s2]; 19 if(K>=n) return 1; 20 } 21 for(int i=2;i<=n;i++) 22 { 23 s1 = Getid(1,i),s2 = Getid(2,i),s3 = Getid(3,i); 24 if(a[s1]==-1||a[s2]==-1) continue; 25 int res = a[s1]+a[s2]; 26 if(a[s3]!=-1&&(res+1)%n!=a[s3]&&res%n!=a[s3]) return 1; 27 if(a[s3]==-1&&st[(res+1)%n]&&st[res%n]) return 1; 28 } 29 return 0; 30 } 31 bool dfs(int k,int p) 32 { 33 if(!k) return 1; 34 if(check()) return 0; 35 int pos = Getid(p,k); 36 if(a[pos]!=-1&&p<3) return dfs(k,p+1); 37 if(p==3) 38 { 39 int s1 = s[1][k]-'A',s2 = s[2][k]-'A'; 40 int now = (a[s1]+a[s2]+b[k])%n; 41 int tmp = (a[s1]+a[s2]+b[k])/n; 42 if(a[pos]!=-1) 43 { 44 if(now!=a[pos]) return 0; 45 else 46 { 47 b[k-1] += tmp; 48 if(dfs(k-1,1)) return 1; 49 b[k-1] -= tmp; 50 return 0; 51 } 52 }else{ 53 if(st[now]) return 0; 54 st[now] = 1; 55 a[pos] = now; 56 b[k-1] += tmp; 57 if(dfs(k-1,1)) return 1; 58 st[now] = 0; 59 a[pos] = -1; 60 b[k-1] -= tmp; 61 return 0; 62 } 63 } 64 for(int i=n-1;i>=0;i--) 65 { 66 if(st[i]) continue; 67 a[pos] = i; 68 st[i] = 1; 69 if(dfs(k,p+1)) return 1; 70 st[i] = 0; 71 a[pos] = -1; 72 } 73 return 0; 74 } 75 int main() 76 { 77 scanf("%d",&n); 78 memset(a,-1,sizeof a); 79 for(int i=1;i<=n;i++) scanf("%s",s[i]+1); 80 if(dfs(n,1)) 81 for(int i=0;i<n;i++) printf("%d ",a[i]); 82 return 0; 83 }