NOI 2001 炮兵陣地

洛谷 P2704 [NOI2001]炮兵陣地

洛谷傳送門php

JDOJ 1105: 炮兵陣地

JDOJ1105傳送門ios

JDOJ 1508: [NOI2001]炮兵陣地

JDOJ1508傳送門數組

Description

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

img

若是在地圖中的灰色所標識的平原上部署一支炮兵部隊,則圖中的黑色的網格表示它可以攻擊到的區域:沿橫向左右各兩格,沿縱向上下各兩格。 圖上其它白色網格均攻擊不到。從圖上可見炮兵的攻擊範圍不受地形的影響。  spa

如今,將軍們規劃如何部署炮兵部隊,在防止誤傷的前提下(保證任何兩支炮兵部隊之間不能互相攻擊,即任何一支炮兵部隊都不在其餘支炮兵部隊的攻擊範圍內) ,在整個地圖區域內最多可以擺放多少我軍的炮兵部隊。設計

Input

第一行包含兩個由空格分割開的正整數,分別表示N和M; 接下來的N行,每一行含有連續的M個字符(‘P’或者‘H’),中間沒有空格。按順序表示地圖中每一行的數據。 N≤100;M≤10。code

Output

僅在第一行包含一個整數K,表示最多能擺放的炮兵部隊的數量。ip

Sample Input

5 4 PHPP PPHH PPPP PHPP PHHPci

Sample Output

6部署

題解:

衆所周知,這是一道狀壓\(DP\)的題目。

衆所周知,設計狀態的時候要考慮邊界。

不能死腦筋,一作狀壓就想以前的題只設計了前面一個狀態來轉移,這道題不同。爲何呢?就像斐波那契數列的遞推式:\(f[i]=f[i-1]+f[i-2]\)。這個轉移是和前兩個數有關的。同理,由於這臺意大利炮能打前面兩格,因此設計狀態的時候天然就要把兩個狀態壓進去:如今的和前一個。

那麼由此得出狀態:

\(dp[i][j][k]\)表示行數爲\(i\)、當前狀態爲\(j\)、上一狀態爲\(k\)時的最大炮數。

這裏狀態0/1表示的不是能不能被炮攻擊到,而只是單純的有沒有炮(若是按前面的設置狀態的話無法統計答案)。

而後咱們考慮轉移的條件。有兩個條件限制了咱們轉移:第一種是原本就不能放大炮。即山地的狀況。第二種是由於容易被其餘大炮打到,因此不能放大炮。

類比於USACO玉米田的一道題,咱們能夠在輸入的時候直接處理出初始狀態,即山地確定不能放炮。用\(F[i]\)數組存儲。

可是咱們發現了一個問題。。這麼設置狀態所需的空間是:100 1024 1024。。必爆無疑。

怎麼辦呢?

在此介紹動態規劃中的經常使用優化方法:滾動數組

代碼:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,cnt;
int map[110][20];
int dp[110][70][70];
int F[110];
int num[110],st[110];
//dp[i][j][k]表示行數爲i,狀態爲j、上一行狀態爲k的時候最多擺放的炮兵部隊的個數。
int lowbit(int x)
{
    int ret=0;
    while(x)
    {
        x-=(x&(-x));
        ret++;
    }
    return ret;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            char a;
            cin>>a;
            if(a=='H')
                map[i][j]=1;
            F[i]=(F[i]<<1)+map[i][j];
        }
    st[++cnt]=0;
    for(int i=1;i<(1<<m);i++)
    {
        if(i&(i<<1))
            continue;
        if(i&(i<<2))
            continue;
        if(i&(i>>1))
            continue;
        if(i&(i>>2))
            continue;
        st[++cnt]=i;
        int tmp=i;
        num[cnt]=lowbit(tmp);
    }
    for(int i=1;i<=cnt;i++)
        if((st[i]&F[1])==0)
            dp[1][i][0]=num[i];
    for(int i=1;i<=cnt;i++)
        if((st[i]&F[2])==0)
            for(int j=1;j<=cnt;j++)
                if((st[i]&st[j])==0 && (st[j]&F[1])==0)
                    dp[2][i][j]=num[i]+num[j];
    for(int i=3;i<=n;i++)
        for(int j=1;j<=cnt;j++)
            if((st[j]&F[i])==0)
                for(int k1=1;k1<=cnt;k1++)
                    if((st[j]&st[k1])==0 && (st[k1]&F[i-1])==0)                  
                        for(int k2=1;k2<=cnt;k2++)             
                            if((st[j]&st[k2])==0 && (st[k1]&st[k2])==0 && (st[k2]&F[i-2])==0)
                                dp[i][j][k1]=max(dp[i][j][k1],dp[i-1][k1][k2]+num[j]);
    int ans=0;
    for(int i=1;i<=cnt;i++)
        for(int j=1;j<=cnt;j++)
            ans=max(ans,dp[n][i][j]);
    printf("%d",ans);
    return 0;
}
相關文章
相關標籤/搜索