POJ 1185 炮兵陣地【狀壓DP+狀態預處理】
阿新 • • 發佈:2018-12-12
題目連結 題意:P處放大炮H不可放,黑色區域為攻擊範圍,求大炮不能相互攻擊的情況下,安裝最多的大炮數. 分析:三維狀壓DP 一開始亂寫了一通,真不知道寫的是什麼,竟然過了樣例,欺騙了自己??? 看了題解要提前把狀態預處理一下,其實也就60個狀態滿足,然後三維狀壓,突然靈感來了。 仔細一想,二維就夠了呀,上去就是寫一個二維狀壓???不過樣例??? 仔細再一想,不對。第i行的所有狀態不能轉移到第i + 1行狀態,按照二維的寫法,第i + 1行的所有狀態會推到第i + 2行的所有狀態,但是有可能第i行的所有狀態不滿足第i + 2行的所有狀態,所以這個方程不對。。。 應該開三維,,把上一狀態也記錄一下,這樣就不會出現上面二維出現的問題。 PS:狀態的預處理值得mark.
#include <cstdio> #include <algorithm> #include <cmath> using namespace std; #define met(s) memset(s, 0, sizeof(s)) #define rep(i, a, b) for(int i = a; i <= b; ++i) template <class T> inline void scan_d(T &ret) { char c; ret = 0; while ((c = getchar()) < '0' || c > '9'); while (c >= '0' && c <= '9') { ret = ret * 10 + (c - '0'), c = getchar();}} typedef long long LL; typedef unsigned long long ull; typedef pair<int, int> pii; const int INF = 0x3f3f3f3f; const int mod = 1e8; const int MAXN = 110; int dp[110][65][65], num[1 << 11]; int a[MAXN], vis[65]; int p = 0, n, m; char ch; bool judge(int x) { if(x & (x << 1)) return false; if(x & (x << 2)) return false; return true; } inline void init() { for(int i = 0; i < (1 << m); ++i) { if(!judge(i)) continue; vis[p++] = i; int x = i; while(x) { if(x & 1) num[i]++; x >>= 1; } // printf("%d %d\n",i, num[i]); } } int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); scanf("%d %d", &n, &m); init(); for(int i = 1; i <= n; ++i) { getchar(); int ans = 0; for(int j = 1; j <= m; ++j) { scanf("%c", &ch); if(ch == 'P') ans = (ans << 1) + 1; else ans = (ans << 1); } a[i] = ans; } for(int i = 0; i < p; ++i) { if((a[1] & vis[i]) != vis[i]) continue; dp[1][i][i] = num[vis[i]]; } for(int i = 0; i < p; ++i) { if((a[2] & vis[i]) != vis[i]) continue; for(int j = 0; j < p; ++j) { if(((a[1] & vis[j]) != vis[j]) || (vis[i] & vis[j])) continue; dp[2][i][j] = max(dp[2][i][j], dp[1][j][j] + num[vis[i]]); } } for(int i = 3; i <= n; ++i) { for(int j = 0; j < p; ++j) { if((a[i] & vis[j]) != vis[j]) continue; for(int u = 0; u < p; ++u) { if((vis[j] & vis[u]) || ((a[i - 1] & vis[u]) != vis[u])) continue; for(int v = 0; v < p; ++v) { if((vis[v] & vis[u]) || (vis[v] & vis[j]) || ((a[i - 2] & vis[v]) != vis[v])) continue; dp[i][j][u] = max(dp[i][j][u], dp[i - 1][u][v] + num[vis[j]]); } } } } int sum = 0; for(int i = 0; i < p; ++i) { for(int j = 0; j < p; ++j) { sum = max(sum, dp[n][i][j]); } } printf("%d\n", sum); return 0; }