[noi2001]炮兵陣地
有乙個\(n\times m\)的網格,第i行第j列有乙個字元\(c[i][j]\)=p or h,分別表示此處為平原和山,只有平原才能放炮,炮的攻擊範圍為向上下左右2格,如圖黑色為攻擊範圍,灰色為放炮的位置
,現在要求求出網格圖中最多可以放炮的個數,並保證炮炮之間不能互相攻擊,\(n\leq 100,m\leq 10\)。
m的範圍已經告訴你可以進製壓縮,但是狀態卻有三種,於是延伸兩種辦法
法一:二進位制壓縮
二進位制當然是最快的,於是可以設\(f[i][j][k]\)表示處理到第i行且第i行的狀態為j,第i-1行狀態為k的能放的最多的炮的數量,顯然設j中有1的位置為有炮的位置,而注意到這樣做會超時,非法狀態太多,於是可以預處理每一行合法的狀態,以此作為轉移依據,設\(a[i][j]\)為第i行第j個合法狀態的二進位制數,自然\(f[i][j][k]\)的j對應的是\(a[i][j]\),k對應的是\(a[i-1][k]\),並預處理\(b[i]\)表示i的二進位制位下有多少個1,於是我們有
\[f[i][j][k]=\max_^(f[i-1][k][l])+b[a[i][j]](!(a[i][j]\&a[i-1][k])\&\&!(a[i][j]\&a[i-2][l])\&\&!(a[i-1][k]\&a[i-2][l]))
\]邊界:\(f[1][i][0]=bit[a[1][i]],i=1,2,..,|a[1]|\)
答案:\(\max_^(f[n][i][j])\)
#include #include #define il inline
#define ri register
using namespace std;
char m[15];
int a[101][501],at[101],
dp[101][501][501],bit[2048];
il int max(int,int);
int main()
if(k<0)a[i][++at[i]]=j;
}}++at[0];
for(int i(1);i<=at[1];++i)dp[1][i][1]=bit[a[1][i]];
for(int i(2);i<=n;++i)
for(int j(1);j<=at[i];++j)
for(int k(1);k<=at[i-1];++k)dp[i][j][k]+=bit[a[i][j]];
}int ans(0);
for(int i(1);i<=at[n];++i)
for(int j(1);j<=at[n-1];++j)
ans=max(ans,dp[n][i][j]);
printf("%d\n",ans);
return 0;
}il int max(int a,int b)
法二:三進製壓縮
因為存在三種狀態,所以自然的想法是三進製壓縮,2表示有炮,1表示炮的上下左右的一格攻擊範圍,因為多進製的合法判斷的速度遠遠不如二進位制,於是我們需要dfs實現轉移,而且要盡可能地多多特判非法狀態。
#include #include #include #define il inline
#define ri register
using namespace std;
char m[11];
int bit[101],dp[101][59050],
b2[59051],y,e,m;
void dfs(int,int,int);
il void read(int&);
int main()
void dfs(int x,int f,int l)
}il void read(int &x)
NOI 2001 炮兵陣地
分析 本來想的和周偉nei胖子差不多 但是感覺時間會炸,於是又苟且看了講解 發現胖子果然用會炸的方法 但是畢竟十幾年前的題了 資料略弱 dp i j k 表示前i行中,第i行狀態為j,第i 1行狀態為k時炮兵的最多數量 狀態均為01的二進位制串 方程很好寫 dp i j k max dp i j k...
NOI2001 炮兵陣地
司令部的將軍們打算在n m的網格地圖上部署他們的炮兵部隊。乙個n m的地圖由n行m列組成,地圖的每一格可能是山地 用 h 表示 也可能是平原 用 p 表示 如下圖。在每一格平原地形上最多可以布置一支炮兵部隊 山地上不能夠部署炮兵部隊 一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示 如果在地圖中的括...
NOI2001 炮兵陣地
司令部的將軍們打算在n m的網格地圖上部署他們的炮兵部隊。乙個n m的地圖由n行m列組成,地圖的每一格可能是山地 用 h 表示 也可能是平原 用 p 表示 如下圖。在每一格平原地形上最多可以布置一支炮兵部隊 山地上不能夠部署炮兵部隊 如果在地圖中的括號所標識的平原上部署一支炮兵部隊,則圖中的黑色的網...