SGU 132 Another Chocolate Maniac 状态压缩DP

感觉不是很好写的一道状态压缩。

dp[i][j][k]表示第 i 行状态为k,第i - 1行状态为 j,具体细节见代码。

内存卡的很死,要用滚动数组。

还有一个比较坑爹的地方是它在输入蛋糕的时候中间可能会出现空行,一开始我用getchar()读,连第一组数据都过不去,后来改成scanf( "%s", str )才过……错了好多次。

  1 #include <cstdio>

  2 #include <cstring>

  3 #include <cstdlib>

  4 #include <algorithm>

  5 

  6 using namespace std;

  7 

  8 const int MAXN = 520;

  9 const int INF = 1 << 20;

 10 

 11 int M, N, all;

 12 int G[100];

 13 int dp[2][MAXN][MAXN];

 14 int TwoPow[MAXN];

 15 int initJ, initK;

 16 int cur, pre;

 17 char str[10];

 18 

 19 void init()

 20 {

 21     memset( G, 0, sizeof(G) );

 22     for ( int i = 1; i <= M; ++i )

 23     {

 24         scanf( "%s", str );

 25         for ( int j = 0; j < N; ++j )

 26         {

 27             if ( str[j] == '*' )

 28                 G[i] |= ( 1 << j );

 29         }

 30         //printf( "G[%d]=%d\n", i, G[i] );

 31     }

 32 

 33     TwoPow[0] = 1;

 34     for ( int i = 1; i <= N; ++i )

 35         TwoPow[i] = ( TwoPow[i - 1] << 1 );

 36 

 37     all = ( 1 << N ) - 1;

 38     return;

 39 }

 40 

 41 //c:当前列, j:当前行的上两行状态, k:当前行的上一行状态

 42 //State:当前行状态, cnt:当前摆放巧克力个数

 43 void DFS( int c, int j, int k, int State, int cnt )

 44 {

 45     //当前行的上两行中出现了2*1的空格

 46     if ( c > 0 && ( ( j & TwoPow[c-1] ) == 0 ) && ( ( k & TwoPow[c-1] )==0 ) )

 47         return;

 48 

 49     //当前行的上一行中出现了1*2的空格

 50     if ( c > 1 && ( ( k & TwoPow[c-1] ) == 0 ) && ( ( k & TwoPow[c-2] )==0 ) )

 51         return;

 52 

 53     if ( c == N )   //当前行摆放完成,状态转移

 54     {

 55         dp[cur][k][State] = min( dp[cur][k][State], dp[pre][initJ][initK] + cnt );

 56         //printf("dp[%d][%d][%d] = %d\n", cur, k, State, dp[cur][k][State] );

 57         return;

 58     }

 59 

 60     DFS( c + 1, j, k, State, cnt );

 61 

 62     //当前行的上一行放2*1的巧克力并影响当前行的状态

 63     if ( ( ( k & TwoPow[c] ) == 0 ) && ( ( State & TwoPow[c] ) == 0 ) )

 64         DFS( c + 1, j, k | TwoPow[c], State | TwoPow[c], cnt + 1 );

 65 

 66     //当前行的上一行放1*2的巧克力

 67     if ( c + 1 < N && ( ( k & TwoPow[c] ) == 0 ) && ( ( k & TwoPow[c + 1] ) == 0 ) )

 68         DFS( c + 1, j, k | TwoPow[c] | TwoPow[c + 1] , State, cnt + 1 );

 69 

 70     return;

 71 }

 72 

 73 void DP()

 74 {

 75     pre = 0;

 76     cur = 1;

 77 

 78     for ( int j = 0; j <= all; ++j )

 79         for ( int k = 0; k <= all; ++k )

 80             dp[0][j][k] = INF;

 81     dp[0][ all ][ G[1] ] = 0;

 82     //printf("**dp[0][%d][%d] = %d\n", all, G[1], dp[0][all][G[1]] );

 83 

 84     for ( int i = 1; i <= M; ++i )

 85     {

 86         for ( int j = 0; j <= all; ++j )

 87             for ( int k = 0; k <= all; ++k )

 88                 dp[cur][j][k] = INF;

 89 

 90         for ( int j = 0; j <= all; ++j )

 91             for ( int k = 0; k <= all; ++k )

 92             {

 93                 if ( dp[pre][j][k] != INF )

 94                 {

 95                     initJ = j, initK = k;

 96                     DFS( 0, j, k, G[i + 1], 0 );

 97                 }

 98             }

 99 

100         pre ^= 1;

101         cur ^= 1;

102     }

103     return;

104 }

105 

106 int main()

107 {

108     while ( scanf( "%d%d", &M, &N ) == 2 )

109     {

110         init();

111         DP();

112 

113         int ans = INF;

114         for ( int i = 0; i <= all; ++i )

115             ans = min( ans, dp[pre][i][0] );

116         printf( "%d\n", ans );

117     }

118     return 0;

119 }

 

你可能感兴趣的:(man)