炮兵陣地
description
司令部的將軍們打算在n*m的網格地圖上部署他們的炮兵部隊。乙個n*m的地圖由n行m列組成,地圖的每一格可能是山地(用"h" 表示),也可能是平原(用"p"表示),如下圖。在每一格平原地形上最多可以布置一支炮兵部隊(山地上不能夠部署炮兵部隊);一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示:
如果在地圖中的灰色所標識的平原上部署一支炮兵部隊,則圖中的黑色的網格表示它能夠攻擊到的區域:沿橫向左右各兩格,沿縱向上下各兩格。圖上其它白色網格均攻擊不到。從圖上可見炮兵的攻擊範圍不受地形的影響。
現在,將軍們規劃如何部署炮兵部隊,在防止誤傷的前提下(保證任何兩支炮兵部隊之間不能互相攻擊,即任何一支炮兵部隊都不在其他支炮兵部隊的攻擊範圍內),在整個地圖區域內最多能夠擺放多少我軍的炮兵部隊。
input
第一行包含兩個由空格分割開的正整數,分別表示n和m;
接下來的n行,每一行含有連續的m個字元('p'或者'h'),中間沒有空格。按順序表示地圖中每一行的資料。n <= 100;m <= 10。
output
僅一行,包含乙個整數k,表示最多能擺放的炮兵部隊的數量。
sample input
5 4sample outputphpp
pphh
pppp
phpp
phhp
6分析:思路很簡單,因為每個位置要麼放一門炮、要麼不放,每行最多只有10個位置,所以可以用位儲存狀態,大體分如下兩步:
1.計算出每行所有的合法狀態,並用位表示。
2.dp~~~
f[p][i][j] = max f[p][i][j]表示第p行取第i種方案,p-1行取第j種方案時的最大值,ct(p,i)表示第p行用第i種方案時用的炮的個數。
求整數x用二進位制表示時1的個數,只需要讓x不斷的執行x &= (x-1)就可以了,執行了多少次就有多少個1。
為什麼呢??可以分兩種情況,如果x最後一位是1,那麼執行一次與運算可以把這個1消掉,但是如果最後一位是0呢??這個時候消掉的是最靠右的乙個1,呵呵,可以簡單的畫一下看看。總之就是逐步消掉最後乙個1,消了幾次就有幾個1啦~~
第乙個**如下:
1 # include2 # include3 # include4由於m很小,最多為10,所以可以對行進行狀態壓縮。二進位制對應位為1表示放炮兵,為0表示空。我們可以事先生成所有有效的狀態,即二進位制數任何兩個1都要相差兩位以上,同時用陣列記下此狀態有多少個炮兵。對於地形也進行狀態壓縮,用1表求高地,0表示平原。判斷某個狀態能否放到某個地形,就是地形狀態為1的地方,放置炮兵狀態一定為0,這點可以用位運算解決。判斷兩個狀態能否放在相鄰行與此相同。using
namespace
std;56
const
int n = 101;7
const
int m = 11;8
const
int inf = 0xffffff;9
10int
n,m;
11int ct[n][65]; //
ct[i][0]表示第i行放置炮的方案數,ct[i][j],j>0 表示第j種方案的狀態
12int tt[1030]; //
tt[i]表示 i 表示成2進製時的1的個數,即放置炮的數目
13int f[n][65][65]; //
f[p][i][j]表示第p行取第i種方案,p-1行取第j種方案時的最大值
14int hash[1030][1030
];15
char
map[n][m];
1617
int max(int x,int
y)20
21//
這一行的狀態
22void init_row(const
int &r,int x,int key)
28if(map[r][x] == '
p' && (key & 1)==0 &&(key & 2)==0) //
可以表示成狀態
29 init_row(r,x+1,(key<<1)+1
);30 init_row(r,x+1,key<<1
);31}32
33bool yes(int x,int y)
41 x>>=1
;42 y>>=1;43
}44if(hash[xx][yy] == -1) hash[xx][yy] = 1
;45 hash[yy][xx] =hash[xx][yy];
46return
hash[xx][yy];47}
4849
void
dp()61}
6263
for(p=3;p<=n;p++)75}
76}77}
78}7980
intmain()90}
91 scanf("
%d%d
",&n,&m);
92for(i=1;i<=n;i++)
93 scanf("%s"
,map[i]);
94for(i=1;i<=n;i++)
98dp();
99 ans = -inf;
100if(n==1
)101
for(i=1;i<=ct[n][0];i++)
102 ans = max(ans,f[n][i][0
]);103
else
108 printf("
%d\n
",ans);
109return0;
110 }
**如下:
1 # include 2**如下:using
namespace
std;34
const
int g = 70;5
const
int n =101;6
const
int m =11;7
8int d[2][g][g];//
滾動陣列
9int ph[n],f[g];//
ph陣列用於判斷狀態在第i行是否滿足在p的平原設定,f陣列則存放滿足的狀態
10int n,m,g;//
g為所有狀態數
1112
int onec(int x)
18return
t;19}20
void dp()33}
34}35}
36}37int
main()48}
49int v = 1
<
50for(i =0,g =0; i< v;i++)
54int
pmax ;
55if(n ==1
)61 printf("%d"
,pmax);
62return0;
63}64 memset(d, 0,sizeof
(d));
65 pmax = 0;66
for(i =0; i < g; i++)74}
75}76if(n ==2)80
dp();
81for(i =0; i < g; i ++)85}
86 printf("%d"
, pmax);
87return0;
88 }
1 # include2 # include3 # include4 # include5 # include6 # include7
using
namespace
std;
8int n,m,sum,num,sta[1
<<11],cot[1
<<11],dp[105][105][105],a[105];9
bool fit(int x,int
y)10
15void
init()
1629 cot[num++]=count;30}
31}32void
dp()
3343
for(int i=2;i<=n;i++)
44for(int j=0;j)
45for(int k=0;k)
4657
}58 printf("
%d\n
",ans);59}
60int
main()
6176}77
getchar();78}
79dp();
80return0;
81 }
另附轉的一篇
POJ 1185 炮兵陣地 動態規劃 狀態壓縮
由於遞推的時候依賴於三個連續層的關係.一開始想著直接三重for迴圈,但是這裡有個問題就是上一層的0位置上包括著上上層是0和1兩種可能,而後者又對當前行有約束,因此該方法不行.當然有乙個辦法就是增加狀態數,讓狀態能夠表示是從1還是從0轉移過來的.這題有個解法是採用多進製的狀態壓縮 網上瞄了別人的一眼解...
poj 1185 炮兵陣地
題目鏈結 題意 在n m的網格地圖上部署炮兵部隊。地圖的每一格可能是山地 用 h 表示 也可能是平原 用 p 表示 如下圖。在每一格平原地形上最多可以布置一支炮兵部隊 山地上不能夠部署炮兵部隊 一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示 如果在地圖中的灰色所標識的平原上部署一支炮兵部隊,則圖中...
POJ 1185 炮兵陣地
include include include include include include include include include include include include include include define sz v int v size define rep i,n ...