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 }

 

posted @ 2017-10-03 22:16  Leohh  阅读(262)  评论(0编辑  收藏  举报