BZOJ 1231 [Usaco2008 Nov]mixup2 混亂的奶牛:狀壓dp + 滾動陣列

Leohh發表於2017-10-03

題目連結: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 }

 

相關文章