题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4529
郑厂长系列故事——N骑士问题
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 642 Accepted Submission(s): 315
Problem Description
郑厂长不是正厂长
也不是副厂长
他根本就不是厂长
还是那个腾讯公司的码农
一个业余时间喜欢下棋的码农
最近,郑厂长对八皇后问题很感兴趣,拿着国际象棋研究了好几天,终于研究透了。兴奋之余,坐在棋盘前的他又开始无聊了。无意间,他看见眼前的棋盘上只摆了八个皇后,感觉空荡荡的,恰好又发现身边还有几个骑士,于是,他想把这些骑士也摆到棋盘上去,当然棋盘上的一个位置只能放一个棋子。因为受八皇后问题的影响,他希望自己把这些骑士摆上去之后,也要满足每2个骑士之间不能相互攻击。
现在郑厂长想知道共有多少种摆法,你能帮助他吗?
骑士的下法:
每步棋先横走或直走一格,然后再往外斜走一格;或者先斜走一格,最后再往外横走或竖走一格(即走“日”字)。可以越子,没有"中国象棋"的"蹩马腿"限制。
也不是副厂长
他根本就不是厂长
还是那个腾讯公司的码农
一个业余时间喜欢下棋的码农
最近,郑厂长对八皇后问题很感兴趣,拿着国际象棋研究了好几天,终于研究透了。兴奋之余,坐在棋盘前的他又开始无聊了。无意间,他看见眼前的棋盘上只摆了八个皇后,感觉空荡荡的,恰好又发现身边还有几个骑士,于是,他想把这些骑士也摆到棋盘上去,当然棋盘上的一个位置只能放一个棋子。因为受八皇后问题的影响,他希望自己把这些骑士摆上去之后,也要满足每2个骑士之间不能相互攻击。
现在郑厂长想知道共有多少种摆法,你能帮助他吗?
骑士的下法:
每步棋先横走或直走一格,然后再往外斜走一格;或者先斜走一格,最后再往外横走或竖走一格(即走“日”字)。可以越子,没有"中国象棋"的"蹩马腿"限制。
Input
输入第一行为一个整数T(1<=T<=8),表示有T组测试数据;
每组数据首先是一个整数N(1<=n<=10),表示要摆N个骑士上去;
接下来是一个8*8的矩阵来描述一个棋盘,’.’表示这个位置是空的,’*’表示这个位置上已经放了皇后了;
数据中的初始棋盘保证是一个合法的八皇后摆法。
每组数据首先是一个整数N(1<=n<=10),表示要摆N个骑士上去;
接下来是一个8*8的矩阵来描述一个棋盘,’.’表示这个位置是空的,’*’表示这个位置上已经放了皇后了;
数据中的初始棋盘保证是一个合法的八皇后摆法。
Output
对每组数据,请在一行内输出一个整数,表示合法的方案数。
Sample Input
2
1
*.......
....*...
.......*
.....*..
..*.....
......*.
.*......
...*....
2
*.......
....*...
.......*
.....*..
..*.....
......*.
.*......
...*....
Sample Output
56
1409
Source
题解:
1.与此题(POJ1185 炮兵阵地)类似。
2.设dp[i][j][s1][s2]为:到第i行,总共放了j个,第i-1行的状态为s1,第i行的状态为s2的情况数。
3.复杂度为8*10*(1<<8)*(1<<8)*(1<<8),理论上是会超时的,但因为有很多剪枝,所以可以把时间复杂度降下去。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const double EPS = 1e-6; 15 const int INF = 2e9; 16 const LL LNF = 9e18; 17 const int MOD = 1e5; 18 const int MAXN = 1<<8; 19 20 int row[10]; 21 int cnt[260]; 22 int dp[9][11][MAXN][MAXN]; 23 24 int main() 25 { 26 int T, n; 27 char str[10]; 28 scanf("%d", &T); 29 while(T--) 30 { 31 scanf("%d", &n); 32 for(int i = 1; i<=8; i++) 33 { 34 scanf("%s", str); 35 row[i] = 0; 36 for(int j = 0; j<8; j++) 37 row[i] += (str[j]=='*')*(1<<j); 38 } 39 40 for(int s = 0; s<MAXN; s++) 41 { 42 cnt[s] = 0; 43 for(int j = 0; j<8; j++) 44 if(s&(1<<j)) 45 cnt[s]++; 46 } 47 48 memset(dp, 0, sizeof(dp)); 49 dp[0][0][0][0] = 1; 50 for(int i = 1; i<=8; i++) 51 { 52 for(int j = 0; j<=n; j++) 53 { 54 for(int s1 = 0; s1<MAXN; s1++) 55 { 56 if(i>2&&(s1&row[i-2])) continue; 57 if(cnt[s1]>n) continue; 58 for(int s2 = 0; s2<MAXN; s2++) 59 { 60 if(i>1&&(s2&row[i-1])) continue; 61 if( (s1&(s2<<2)) || (s1&(s2>>2)) ) continue; 62 if(cnt[s2]>n) continue; 63 for(int s3 = 0; s3<MAXN; s3++) 64 { 65 if(s3&row[i]) continue; 66 if( (s1&(s3<<1)) || (s1&(s3>>1)) ) continue; 67 if( (s2&(s3<<2)) || (s2&(s3>>2)) ) continue; 68 if(j-cnt[s3]<0) continue; 69 dp[i][j][s2][s3] += dp[i-1][j-cnt[s3]][s1][s2]; 70 } 71 } 72 } 73 } 74 } 75 76 LL ans = 0; 77 for(int s1 = 0; s1<MAXN; s1++) 78 for(int s2 = 0; s2<MAXN; s2++) 79 ans += dp[8][n][s1][s2]; 80 printf("%lld ", ans); 81 } 82 }
滚动数组:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const double EPS = 1e-6; 15 const int INF = 2e9; 16 const LL LNF = 9e18; 17 const int MOD = 1e5; 18 const int MAXN = 1<<8; 19 20 int row[10]; 21 int cnt[260]; 22 int dp[2][11][MAXN][MAXN]; 23 24 int main() 25 { 26 int T, n; 27 char str[10]; 28 scanf("%d", &T); 29 while(T--) 30 { 31 scanf("%d", &n); 32 for(int i = 1; i<=8; i++) 33 { 34 scanf("%s", str); 35 row[i] = 0; 36 for(int j = 0; j<8; j++) 37 row[i] += (str[j]=='*')*(1<<j); 38 } 39 40 for(int s = 0; s<MAXN; s++) 41 { 42 cnt[s] = 0; 43 for(int j = 0; j<8; j++) 44 if(s&(1<<j)) 45 cnt[s]++; 46 } 47 48 memset(dp[0], 0, sizeof(dp[0])); 49 dp[0][0][0][0] = 1; 50 for(int i = 1; i<=8; i++) 51 { 52 memset(dp[i%2], 0, sizeof(dp[i%2])); 53 for(int j = 0; j<=n; j++) 54 { 55 for(int s1 = 0; s1<MAXN; s1++) 56 { 57 if(i>2&&(s1&row[i-2])) continue; 58 if(cnt[s1]>n) continue; 59 for(int s2 = 0; s2<MAXN; s2++) 60 { 61 if(i>1&&(s2&row[i-1])) continue; 62 if( (s1&(s2<<2)) || (s1&(s2>>2)) ) continue; 63 if(cnt[s2]>n) continue; 64 for(int s3 = 0; s3<MAXN; s3++) 65 { 66 if(s3&row[i]) continue; 67 if( (s1&(s3<<1)) || (s1&(s3>>1)) ) continue; 68 if( (s2&(s3<<2)) || (s2&(s3>>2)) ) continue; 69 if(j-cnt[s3]<0) continue; 70 dp[i%2][j][s2][s3] += dp[(i+1)%2][j-cnt[s3]][s1][s2]; 71 } 72 } 73 } 74 } 75 } 76 77 LL ans = 0; 78 for(int s1 = 0; s1<MAXN; s1++) 79 for(int s2 = 0; s2<MAXN; s2++) 80 ans += dp[0][n][s1][s2]; 81 printf("%lld ", ans); 82 } 83 }