【狀壓DP】【cofun1368】炮兵陣地

【cofun1368】炮兵陣地

Description
司令部的將軍們打算在NM的網格地圖上部署他們的炮兵部隊。一個NM的地圖由N行M列組成,地圖的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下圖。在每一格平原地形上最多可以佈置一支炮兵部隊(山地上不能夠部署炮兵部隊);一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示:

如果在地圖中的灰色所標識的平原上部署一支炮兵部隊,則圖中的黑色的網格表示它能夠攻擊到的區域:沿橫向左右各兩格,沿縱向上下各兩格。圖上其它白色網格均攻擊不到。從圖上可見炮兵的攻擊範圍不受地形的影響。
現在,將軍們規劃如何部署炮兵部隊,在防止誤傷的前提下(保證任何兩支炮兵部隊之間不能互相攻擊,即任何一支炮兵部隊都不在其他支炮兵部隊的攻擊範圍內),在整個地圖區域內最多能夠擺放多少我軍的炮兵部隊。

Input Format
文件的第一行包含兩個由空格分割開的正整數,分別表示N和M; 接下來的N行,每一行含有連續的M個字符(‘P’或者‘H’),中間沒有空格。按順序表示地圖中每一行的數據。 N≤100;M≤10。
Output Format
文件僅在第一行包含一個整數K,表示最多能擺放的炮兵部隊的數量。

Sample Input
5 4
PHPP
PPHH
PPPP
PHPP
PHHP
Sample Output
6


  • 分析:
    • m <= 10
      來個愉快地狀壓吧~
      ①用二進制表示每行的地形( 0:平原P/ 1:山地H)。
      ②dfs出每行的情況,注意要考慮炮兵的攻擊範圍,情況也壓進二進制 (0:沒放炮兵/ 1:放了炮兵),存在s數組中。
      ③用鄰接表存儲可以放在相鄰一行和兩行的每行情況。
      ④轉移方程:
f[i][j][e[k].to] = max(f[i][j][e[k].to], f[i - 1][e[k].to][e[l].to] + __builtin_popcount(s[j]));

f[i][j][e[k].to] : 枚舉到第i行爲止,第i行情況爲j,第i-1行情況爲e[k].to;
__builtin_popcount(x)函數表示計算二進制數x中1的個數,詳見→神犇的整理

【前幾天剛學的時候還看了挺久的課件才%出來ORZ


  • 代碼:
#include <bits/stdc++.h>
 using namespace std;

 const int MN = 105;
 struct info{
    int to, next;
 }e[MN * MN];
 int n, m, num, i, j, k, l, ans, p[MN], s[MN], h[MN], f[MN][MN][MN];
 char c[15];

 inline void add(int u, int v)
 {
    e[++ k].to = v;
    e[k].next = h[u];
    h[u] = k;
 }

 inline void dfs(int d, int now)
 {
    if (d == m)
    {
        s[++ num] = now;
        return;
     }

    dfs(d + 1, now << 1);
    if (((now & 1) == 0) && ((now & 2) == 0))
        dfs(d + 1, (now << 1) + 1);
 }

 int main()
 {

    scanf("%d%d\n", &n, &m);
    for(i = 1; i <= n; i ++)
    {
        scanf("%s\n", c);
        p[i] = 0;
        for(j = 0; j < m; j ++)
        {

            p[i] = p[i] << 1;
            if (c[j] == 'H')
                p[i] += 1;
         }
     } 
    //讀入&①
    num = 0;
    dfs(0, 0);
    //② 
    for(i = k = 1; i <= num; i ++)
        for(j = i; j <= num; j ++)
        if ((s[i] & s[j]) == 0)
        {
            add(i, j);
            add(j, i);
         } 
    //③         
    for(i = 0; i <= n; i ++)
        for(j = 0; j <= num; j ++)
            for(k = 0; k <= num; k ++)
                f[i][j][k] = -0x3f3f3f;
    f[0][1][1] = 0;
    //初始化           
    for(i = 1; i <= n; i ++)
        for(j = 1; j <= num; j ++)
        if ((p[i] & s[j]) == 0)//該放法被地形允許
            for(k = h[j]; k; k = e[k].next)
                for(l = h[j]; l; l = e[l].next)
                    f[i][j][e[k].to] = max(f[i][j][e[k].to], f[i - 1][e[k].to][e[l].to] + __builtin_popcount(s[j]));
    //狀態轉移&④ 
    ans = 0;
    for(i = 1; i <= num; i ++)
        for(j = 1; j <= num; j ++)
            ans = max(ans, f[n][i][j]);
    printf("%d", ans);
    //統計並輸出答案 
    return 0;

 }

晚上好~ : )

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