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 }

 

转载于:https://www.cnblogs.com/GBRgbr/p/3217333.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值