洛谷2704 NOI2001 炮兵陣地

2022-04-29 20:03:11 字數 1320 閱讀 4234

題目戳這裡

solution

狀壓dp很好的入門題,用熟練位運算貌似也沒那麼難。

首先分析一下題目:

看見n=100,m=10,立馬就想到了狀壓,看起來也像dp,所以我們還是採用行號為階段的狀壓dp。

因為每個炮兵可以攻擊到上面兩行的範圍,所以列舉i行狀態時需要知道i-1和i-2行的狀態。我們把每一行的狀態看成乙個m位的二進位制數,第p位為1代表該行第p列放置了乙個炮兵,0代表沒有。

在dp前,我們先預處理出集合s,代表「相鄰兩個1的距離不小於3」的所有m位二進位制數,g陣列儲存對應s集合中某個數含有的1的個數。然後還需要預處理出1行和2行狀態。

那麼狀態定義也很明顯了,f[j][k][i]表示第i行狀態為j,第i-1行狀態為k的方案數,那麼只需列舉上一行狀態和上兩行狀態便可以轉移。

雖然m為的二進位制數有\(2^m\)個,但是我們只列舉s集合裡面的數(其他的不合法),所以時間複雜度為\(o(n|s|^2)\),事實上s集合非常小。

coding

#includeusing namespace std;

const int n = 105;

int num,s[n*20],ans,n,m,f[n*20][n*20][101],sum[n*20],a[n],g[n];

int count(int x)

return num;

}int main()

for(int i=1;i<=num;i++)//預處理前兩行

for(int j=1;j<=num;j++)

if(((s[i]&s[j])==0)&&((s[j]&a[2])==0)) f[i][j][2]=max(f[i][j][2],f[0][i][1]+g[j]);

for(int i=3;i<=n;i++)

for(int j=1;j<=num;j++)

if((a[i]&s[j])==0)

for(int k=1;k<=num;k++)

if((s[k]&s[j])==0)

for(int last=1;last<=num;last++)

if(((s[last]&s[k])==0)&&((s[last]&s[j])==0)) f[k][j][i]=max(f[k][j][i],f[last][k][i-1]+g[j]);

for(int i=1;i<=num;i++)

for(int j=1;j<=num;j++)

ans=max(ans,f[i][j][n]);

cout

}

洛谷2704 NOI2001 炮兵陣地

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

NOI2001 炮兵陣地 洛谷2704

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

NOI2001 炮兵陣地 洛谷2704

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