題目戳這裡
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 表示 如下圖。在每一格平原地形上最多可以布置一支炮兵部隊 山地上不能夠部署炮兵部隊 一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示 如果在...