POJ 1185 炮兵佈陣(狀壓dp)

炮兵佈陣

題解:先考慮一維的情況,dp[i]dp[i]ii行所最多能擺放的炮兵部隊的數量,顯然無法滿足無後效性,無法遞推。再考慮加一維,dp[i][j]dp[i][j]表示第ii行佈局爲jj的情況下所最多能擺放的炮兵部隊的數量,此時依然無法遞推,因爲每一個炮兵影響的範圍是前後兩格和左右兩格,所以在第i1i-1行佈局爲kk的時候無法分辨與佈局jj是否相容。因此考慮再加一維,dp[i][j][k]dp[i][j][k]表示第ii行佈局爲jji1i-1行佈局爲kk時最多能擺放的炮兵部隊的數量。dp[i][j][k]=max{dp[i1][k][m]+num[j]}dp[i][j][k] = max\{dp[i-1][k][m]+num[j]\}此時佈局jjkk必須相容,否則dp[i][j][k]=0dp[i][j][k]= 0num[j]num[j]表示佈局爲jj中的炮兵數量。我們發現jjmm必須相容,kkmm必須相容。發現可以滿足無後效性。
至於邊界即{dp[1][j][1]=num[j]dp[1][i][j]=max{dp[1][j][1]+num[j]}\begin{cases} dp[1][j][1]=num[j]\\\\ dp[1][i][j] = max\{dp[1][j][1]+num[j] \} \end{cases}

代碼

#include<cstdio>
#include<cstring>
#define max(a,b) ((a) > (b) ? (a) : (b))
using namespace std;

int n,m;
char map[110][20], num[110], top;
int state[70], cur[70], dp[110][70][70];

bool ok(int x) {
	if((x & (x << 1)) || (x & (x << 2))) return 0;
	return 1;
}

int getNum(int x) {
	int cnt = 0;
	while(x) {
		cnt++;
		x &= (x - 1);
	}
	return cnt;
}

void init() {
	top = 0;
	for(int i = 0; i < (1 << m); ++i) 
		if(ok(i))  state[++top] = i;
	memset(dp,-1,sizeof dp);
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
	scanf("%d%d",&n,&m);
	init();
	for(int i = 1; i <= n; ++i)
		scanf("%s",map[i] + 1);
	for(int i = 1; i <= n; ++i) {
		cur[i] = 0;
		for(int j = 1; j <= m; ++j){
			if(map[i][j] == 'H') cur[i] |= (1 << (j - 1));
		}
	}
	for(int j = 1; j <= top; ++j) {
		num[j] = getNum(state[j]);
		if((state[j] & cur[1]) == 0) 
			dp[1][j][1] = num[j];
	}
	for(int i = 2; i <= n; ++i) { //第i行
		for(int j = 1; j <= top; ++j) { //第i行佈局爲j
			if(state[j] & cur[i]) continue;
			for(int k = 1; k <= top; ++k) { //第i-1行佈局爲k
				if(state[j] & state[k]) continue;
				for(int m = 1; m <= top; ++m) {
					if(state[j] & state[m]) continue; // j與m相容
					if(state[k] & state[m]) continue; // k與m相容
					if(dp[i - 1][k][m] == -1) continue; 
					dp[i][j][k] = max(dp[i][j][k], dp[i - 1][k][m] + num[j]);
				}
			}
		}
	}
	int ans = 0;
	for(int i = 1; i <= top; ++i)
		for(int j = 1; j <= top; ++j) ans = max(ans, dp[n][i][j]);
	printf("%d\n",ans);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章