• HDU4529 郑厂长系列故事——N骑士问题 —— 状压DP


    题目链接: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个骑士之间不能相互攻击。
      现在郑厂长想知道共有多少种摆法,你能帮助他吗?

    骑士的下法:
      每步棋先横走或直走一格,然后再往外斜走一格;或者先斜走一格,最后再往外横走或竖走一格(即走“日”字)。可以越子,没有"中国象棋"的"蹩马腿"限制。
     
    Input
    输入第一行为一个整数T(1<=T<=8),表示有T组测试数据;
    每组数据首先是一个整数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 }
    View Code

    滚动数组:

     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 }
    View Code
  • 相关阅读:
    ubuntu重新安装mysql
    linux基本命令
    ubuntu启用root用户
    cada的常规使用
    如果有人对我的mysql的笔记感兴趣请联系我,互相学习
    10、mysql查看进程
    09、Mysql 查询是否锁表
    08、查看锁记录等待时间:
    针对发送网络附件的java方法(使用Apache的jar包调用)
    mysql的卸载重装+导入大量数据失败的解决方案+工具执行和项目执行结果不同
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/8509203.html
Copyright © 2020-2023  润新知