HDU 4539 鄭廠長系列故事——排兵佈陣(狀態壓縮DP)
阿新 • • 發佈:2018-11-08
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #define N 110 #define M 200 using namespace std; int n, m, a[N]; int dp[N][M][M], cnt, num[M], sum[M]; ///dp[i][j][k] 表示第i行的j狀態 i-1行的k狀態 的最優解 bool conflict(int x) { return (x&(x<<2)) || (x&(x>>2));///第x-2個和x+2個位是否有人, // 有的話就不符合條件 } int getsum(int x) { ///1的個數,即放多少個兵 int sum = 0; while(x) { if(x & 1) sum++; x >>= 1; } return sum; } void init() { cnt = 0; for(int i = 0; i < (1<<m); i++) { ///預處理,壓縮 if(!conflict(i)) { num[cnt] = i; sum[cnt++] = getsum(i); } } } int main() { freopen("data.in", "r", stdin); while(~scanf("%d%d", &n, &m)) { memset(a, 0, sizeof a); for(int i = 0; i < n; i++) { for(int j = 0; j < m; j++) { int x; scanf("%d", &x); if(x == 0) continue;///方便計算,把0存為1 a[i] |= (1<<j); } } init(); memset(dp, 0, sizeof dp); for(int i = 0; i < cnt; i++) { ///處理第一行 if((a[0] | num[i]) != a[0])//不符合原來矩陣情況 continue; dp[0][i][0] = sum[i]; } ///遞推,要考慮三行的情況, for(int i = 1; i < n; i++) { //第一行 for(int j = 0; j < cnt; j++) { if((a[i] | num[j]) != a[i]) continue; ///第一行與原來矩陣有衝突 for(int k = 0; k < cnt; k++) { ///第二行 if((a[i-1] | num[k]) != a[i-1])//不符合原來矩陣情況 continue; if(((num[k] << 1) & num[j]) || ((num[k] >> 1) & num[j])) continue; //i-1行 int Max = -1; for(int l = 0; l < cnt; l++) { ///第三行 if(num[j] & num[l]) continue; if(((num[l] << 1) & num[k]) || ((num[l] >> 1) & num[k])) continue; Max = max(Max,dp[i-1][k][l]); } dp[i][j][k] = Max + sum[j]; } } } int Max = -1; for(int i = 0; i < cnt; i++) for(int j = 0; j < cnt; j++) Max = max(Max, dp[n-1][i][j]); printf("%d\n",Max); } return 0; }