zoukankan      html  css  js  c++  java
  • bzoj 1087 互不侵犯King

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1087

    题解:
      刚开始光想着爆搜、打表,观摩大犇们的博客,才薛习了正解:状态压缩DP

      对于每一格,只有放国王或者不放国王两种可能,所以一行的状态可以表示为一个01串,可以想到压缩成一个十进制数存储,计算出所有可能的状态并编号,然后将互相矛盾的状态标记出来

      之后开始DP,f[i][j][k]表示第i行,第j种状态,放k个棋子的状态数

      四层循环,枚举行数i、状态数j、放的国王的个数l、上一行的状态m

      当满足两行的状态不矛盾,并且两种状态的国王数不超过l时,状态转移方程:
      f[i][j][l]+=f[i-1][m][l-j状态的国王数]

      最后,将f[n][1...状态总数][k]加起来得到结果

     1 #include<cstdio>
     2 #define MAXN 100
     3 int n,k,num_of_status,status[MAXN],status_sum[MAXN];//num_of_status记录状态总数,status记录十进制压缩后的状态,status_sum记录某种状态放了几个国王
     4 long long ans,f[MAXN]/*行号*/[MAXN]/*状态编号*/[MAXN*10]/*放的国王数*/;
     5 bool status_can[MAXN][MAXN];//某两种状态是否矛盾
     6 void dfs(int x,int y,int z)//计算一行中所有状态,表示这一行放x个棋子,用了y个格子,z表示十进制压缩后的状态
     7 {
     8     status[++num_of_status]=z;
     9     status_sum[num_of_status]=x;
    10     if(x>=(n+1)/2||x>=k)return;//已经没有足够的空间放国王或者国王已经放完了
    11     for(int i=y+2;i<=n;i++)dfs(x+1,i,z+(1<<(i-1)));
    12 }
    13 void get_can()
    14 {
    15     for(int i=1;i<=num_of_status;i++)
    16     {
    17         for(int j=1;j<=num_of_status;j++)
    18         {
    19             if(!((status[i]&status[j])||((status[i]>>1)&status[j])||(status[i]&(status[j]>>1))))status_can[i][j]=status_can[j][i]=true;//注意左下和右下也不能放国王,所以还要将这一行左移一位或者右移一位判断
    20         }
    21     }
    22     for(int i=1;i<=num_of_status;i++)f[1][i][status_sum[i]]=1;//初始化第一行的状态
    23 }
    24 int main()
    25 {
    26     scanf("%d%d",&n,&k);
    27     dfs(0,-1,0);
    28     get_can();
    29     for(int i=2;i<=n;i++)
    30     {
    31         for(int j=1;j<=num_of_status;j++)
    32         {
    33             for(int l=0;l<=k;l++)
    34             {
    35                 if(status_sum[j]>l)continue;
    36                 for(int m=1;m<=num_of_status;m++)
    37                 {
    38                     if(status_can[m][j]&&status_sum[j]+status_sum[m]<=l)
    39                     {
    40                         f[i][j][l]+=f[i-1][m][l-status_sum[j]];
    41                     }
    42                 }
    43             }
    44         }
    45     }
    46     for(int i=1;i<=num_of_status;i++)ans+=f[n][i][k];
    47     printf("%lld
    ",ans);
    48     return 0;
    49 }
  • 相关阅读:
    ==和equals
    java 多重继承
    java单例模式
    基础小知识
    print流之错误日志
    print流
    实现读文本文件(IOl流)
    缓冲流(数据的复制粘贴)IO流
    力扣20题、1047(括号合法性,删除字符串中的所有相邻重复项)
    力扣232题、225题(栈实现队列,队列实现栈)
  • 原文地址:https://www.cnblogs.com/xqmmcqs/p/5994888.html
Copyright © 2011-2022 走看看