• BZOJ 1231 [Usaco2008 Nov]mixup2 混乱的奶牛:状压dp + 滚动数组


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

    题意:

      给你n个数字s[i],问你有多少个排列,使得任意相邻两数字之差的绝对值大于m。

    题解:

      表示状态:

        dp[i][j][state] = arrangements

        i:考虑到第i个位置。

        j:上一个数字是s[j]。(j = n表示没有上一个数字)

        state:表示哪些数字已经被选过。

      找出答案:

        ans = ∑ dp[n][j][(1<<n)-1]

      如何转移:

        now: dp[i][j][state]

        枚举第i个位置要放数字s[k]。

        dp[i+1][k][state|(1<<k)] += dp[i][j][state]

        转移条件:

          (1)abs(s[j]-s[k])>m || j==n

            与上一个数字之差的绝对值 > m,或没有上一个数字。

          (2)!((state>>k)&1)

            数字s[k]还没被选过。

      边界条件:

        dp[0][n][0] = 1

        others = 0

      优化:

        因为dp要用long long存,空间正好爆了。。。

        第一维改成滚动数组。

        注意:当前为dp[i&1],要用dp[(i+1)&1],要把dp[(i+1)&1]全部设为0。

          即:memset(dp[(i+1)&1],0,sizeof(dp[(i+1)&1]))

    AC Code:

     1 // state expression:
     2 // dp[i][j][state] = arrangements
     3 // i: considering ith pos
     4 // j: last cow
     5 // state: state of selection
     6 //
     7 // find the answer:
     8 // sigma dp[n][j][(1<<n)-1]
     9 //
    10 // transferring:
    11 // now: dp[i][j][state]
    12 // dp[i+1][k][state|(1<<k)] += dp[i][j][state]
    13 // abs(s[j]-s[k])>m || j==n
    14 // !((state>>k)&1)
    15 //
    16 // boundary:
    17 // dp[0][n][0] = 1
    18 // others = 0
    19 #include <iostream>
    20 #include <stdio.h>
    21 #include <string.h>
    22 #include <stdlib.h>
    23 #define MAX_N 17
    24 #define MAX_S 65540
    25 
    26 using namespace std;
    27 
    28 int n,m;
    29 int s[MAX_N];
    30 long long ans=0;
    31 long long dp[2][MAX_N][MAX_S];
    32 
    33 void read()
    34 {
    35     cin>>n>>m;
    36     for(int i=0;i<n;i++)
    37     {
    38         cin>>s[i];
    39     }
    40 }
    41 
    42 void solve()
    43 {
    44     memset(dp,0,sizeof(dp));
    45     dp[0][n][0]=1;
    46     for(int i=0;i<n;i++)
    47     {
    48         memset(dp[(i+1)&1],0,sizeof(dp[(i+1)&1]));
    49         for(int j=0;j<=n;j++)
    50         {
    51             for(int state=0;state<(1<<n);state++)
    52             {
    53                 if(dp[i&1][j][state])
    54                 {
    55                     for(int k=0;k<n;k++)
    56                     {
    57                         if((abs(s[j]-s[k])>m || j==n) && !((state>>k)&1))
    58                         {
    59                             dp[(i+1)&1][k][state|(1<<k)]+=dp[i&1][j][state];
    60                         }
    61                     }
    62                 }
    63             }
    64         }
    65     }
    66     for(int i=0;i<n;i++)
    67     {
    68         ans+=dp[n&1][i][(1<<n)-1];
    69     }
    70 }
    71 
    72 void print()
    73 {
    74     cout<<ans<<endl;
    75 }
    76 
    77 int main()
    78 {
    79     read();
    80     solve();
    81     print();
    82 }
  • 相关阅读:
    在VMWare中增加Linux文件系统空间
    linux shell 字符串操作(长度,查找,替换)详解
    linux chmod命令参数及用法详解文件文件夹权限设定命令
    Linux分割日志计划任务(原创)
    写日志C#程序
    2011年底,数家大型网站数据库被窃取分析报告(原创)
    ThinkPad SL400全驱动
    东辰信竞学子——从今天开始重新出发!
    CentOS7下安装mysql8027
    arcgis基础
  • 原文地址:https://www.cnblogs.com/Leohh/p/7624677.html
Copyright © 2020-2023  润新知