luogu2704 炮兵陣地 狀態壓縮DP

2022-06-30 12:33:15 字數 1698 閱讀 1266

題目大意:乙個n*m的地圖由n行m列組成,地圖的每一格可能是山地(用「h」 表示),也可能是平原(用「p」表示),在每一格平原地形上最多可以布置一支炮兵部隊,能攻擊到的區域:沿橫向左右各兩格,沿縱向上下各兩格。保證任何兩支炮兵部隊之間不能互相攻擊時,最多能放置的炮兵數。n<=100,n<=10

動規先要確定方向,我們規定其為從上到下。每一排的最優值與其前兩排的各個炮兵的放置位置都有關,所以為了使得dp以後的排時能夠找到其對應的前兩排的各個炮兵的放置位置所對應的最優值,dp內的引數有:

當前的排數i

當前排的炮兵狀態curs

上一排的炮兵狀態prevs

定義上兩排的炮兵狀態為grands,這樣,對於每個滿足二進位制數內兩個1距離超過2的curs,prevs,grands(因為m是固定的,所以可以在dp前將其算好,叫做rowss)遞迴式為:

foreach dp(i, curs, prevs) (curs屬於i排平原 且 prevs屬於i-1排平原 且 curs∩prevs=空),其值 = max foreach dp(i-1, prevs, grands)+curs內1的數量 (grands屬於i-2排平原 且 curs∩grands為空 且 prevs∩grands為空)

curs內1的數量可以在算完rowss時一起求出。

一切陣列從0開始,dp開始時先特殊處理i=0和1的情況,避免以後在各種特判中搞暈。

dp要用三層滾動陣列儲存,否則應該會爆空間。

注意:

#include #include #include #include #include #include #include using namespace std;

const int max_n = 110, max_m = 10, ninf = 0xcfcfcfcf;

int map[max_n], dp[3][1 << (max_m + 1)][1 << (max_m+1)], colss[1<<(max_m+1)], colnums[1<<(max_m+1)];

char cmap[max_n][max_m];

int n, m, scnt;

#define loop0(i, n) for(int i=0; i<(n); i++)

#define loopfrom(i, m, n) for(int i=(m); i<(n); i++)

#define update(x, y) x=max(x, y)

#define in(b, a) (((b)&(a))==(b))

#define intersect(x, y) ((x)&(y))

#define join(a, x) ((a)|=(1<<(x)))

int bcnt(int x)

return ans;

}int calcols(int *rowss, int m)

return cnt;

}//s:state

int proceed()

} loop0(j, scnt)

}} }

loopfrom(i,2,n)}}

}}

} }int ans = 0;

loop0(j, scnt)

}} return ans;

}int main()

scnt = calcols(colss, m);

printf("%d\n", proceed());

return 0;

}

luogu2704 狀壓DP 炮兵陣地

題目描述 司令部的將軍們打算在nm的網格地圖上部署他們的炮兵部隊。乙個nm的地圖由n行m列組成,地圖的每一格可能是山地 用 h 表示 也可能是平原 用 p 表示 如下圖。在每一格平原地形上最多可以布置一支炮兵部隊 山地上不能夠部署炮兵部隊 一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示 如果在地圖...

luogu2704 NOI2001 炮兵陣地

題目鏈結 因為m 10,考慮狀壓dp 先dfs搜出所有可能狀態 f i j k 表示上上行是 i,上行是 j,第 k 行取得的最大值 但如果直接開滿陣列,mle 考慮滾動陣列 此題只需保留2個狀態,上上行,上行 所以用四層迴圈列舉 超時 考慮剪枝 放進上上行時先與題述條件對比 放入上行是與上上行和題...

題解 P2704 炮兵陣地

這道題和p1879 usaco06nov 玉公尺田corn fields有類似的地方,但這道題可以看為那道題的公升級版,所以我建議沒做過玉公尺田的可以先做一下玉公尺田和p1896 scoi2005 互不侵犯king。解此題的關鍵在於要知道第i行的狀態是由前兩行的狀態決定的,所以要預處理出第一行和第二...