http://codeforces.com/problemset/problem/111/C
一個n*m的棋盤,初始狀態下每個格子上都有一隻蜘蛛,蜘蛛一步可以上下左右走,也可以停在原地,問,走一步,能使棋盤最多產生多少個空位
考慮到n*m較小,所以有一維<=6,這時候就應該想到可以用狀態壓縮DP解決
dp[i][j][k]表示前i行,第i行的狀態為j,第i+1行的狀態為k時所能產生的最多空位的數量(不包括第i+1行),由於不包括第i+1行,所以在狀態轉移判斷某些狀態能否轉移過來的時候就簡單多了,只需要判斷中間那一行能否恢複成初始狀態即可(也就是目前狀態能否從初始狀態變過來)
參考代碼
#include <cstdio>#include <cstring>#include <set>#include <string>#include <iostream>#include <cmath>#include <vector>#include <map>#include <stack>#include <time.h>#include <queue>#include <cstdlib>#include <algorithm>using namespace std;#define lowbit(x) ((x)&(-(x)))#define sqr(x) ((x)*(x))#define PB push_back#define MP make_pair#define foreach(it, x) for(typeof(x.begin()) it = x.begin(); it!=x.end();it++)typedef unsigned long long ULL;typedef long long lld;typedef vector<int> VI;typedef vector<string> VS;typedef pair<int,int> PII;#define rep(i,n) for(int i=0;i<n;i++)#define For(i,a,b) for(int i=a;i<=b;i++)#define CL(x) memset(x, 0, sizeof(x))#define CLX(x, y) memset(x, y, sizeof(x))template <class T> T two(T x) {return 1<<x ;}template <class T> void Min(T &x, T y){if(y < x) x = y;}template <class T> void Max(T &x,T y){if(y > x) x = y;}int dp[45][1<<6][1<<6],n,m;int full;inline int get(int x){ int cnt = 0; rep(i,m) if(x>>i&1) cnt++; return m - cnt;}bool check(int a,int b,int c){ int s = b | (b<<1) | (b>>1) | a | c; return ( s & (full-1) )== (full-1);}int State[1<<6];int main() { scanf("%d%d",&n,&m); if(n < m) swap(n,m); full = two(m) ; rep(i,n+1) rep(j,full) rep(k,full) dp[i][j][k] = -111111; rep(i,full) dp[0][0][i] = 0,State[i] = get(i); rep(i,n) rep(j,full) rep(k,full) rep(l,full) if(check(j,k,l)) Max( dp[i+1][k][l] , dp[i][j][k] + State[k] ); int ans = 0; rep(i,full) Max(ans,dp[n][i][0]); cout<<ans<<endl;}