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 }