您的位置:首页 > 其它

HDU 4539 郑厂长系列故事——排兵布阵 && POJ 1185 炮兵阵地 (状态DP)

2014-03-13 17:42 337 查看


郑厂长系列故事——排兵布阵

Problem Description

  郑厂长不是正厂长

  也不是副厂长

  他根本就不是厂长

  事实上

  他是带兵打仗的团长

  一天,郑厂长带着他的军队来到了一个n*m的平原准备布阵。

  根据以往的战斗经验,每个士兵可以攻击到并且只能攻击到与之曼哈顿距离为2的位置以及士兵本身所在的位置。当然,一个士兵不能站在另外一个士兵所能攻击到的位置,同时因为地形的原因平原上也不是每一个位置都可以安排士兵。

  现在,已知n,m 以及平原阵地的具体地形,请你帮助郑厂长计算该阵地,最多能安排多少个士兵。

Input

输入包含多组测试数据;

每组数据的第一行包含2个整数n和m (n <= 100, m <= 10 ),之间用空格隔开;

接下来的n行,每行m个数,表示n*m的矩形阵地,其中1表示该位置可以安排士兵,0表示该地形不允许安排士兵。

Output

请为每组数据计算并输出最多能安排的士兵数量,每组数据输出一行。

Sample Input

6 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0


Sample Output

2


每一行的状态只与前面两行的状态有关,每行可以压缩为二进制的集合,设状态dp[i][j][k]为第i行为集合j,第i-1行为集合k,
得出状态方程dp[i][j][k] = max{dp[i-1][k][r]+cnt[j] | 状态i,j,k要能够共存}
对于每一行可能出现的组合,可以先预处理出每一种有效状态。



int dp[2][200][200] ;  //dp[row][i][j] ,(截止到)row行状态为第i种,row-1行状态为第j种,的最大人数
int cannot[101] ;
int N , M ;

int ok(int x){    //同行
if(x & (x<<2))
return 0 ;
if(x & (x>>2))
return 0 ;
return 1 ;
}

int Count(int x){  //状态x的人数
int sum = 0 ;
while(x){
if(x&1)
sum++ ;
x>>=1 ;
}
return sum ;
}

//求基本状态,与对应的人数
void get_all_states(vector<int> &states , vector<int> &people){
int i ;
states.clear() ;
people.clear() ;
for(i = 0 ; i < (1<<M) ; i++){
if(ok(i)){
states.push_back(i) ;
people.push_back(Count(i)) ;
}
}
}

int DP(){
int i , j , k ,row , sum = 0 ;
vector<int> states ;
vector<int> people ;
get_all_states(states , people) ;
memset(dp , -1 , sizeof(dp)) ;
for(i = 0 ; i < states.size() ; i++){
if(states[i] & cannot[1])
continue ;
dp[1][i][0] = people[i];    //初值
}
for(row = 2 ; row <= N ; row++){
for(i = 0 ; i < states.size() ; i++){
if(states[i] & cannot[row])
continue ;
for(j = 0 ; j < states.size() ; j++){
if(states[j] & cannot[row-1])
continue ;
if(states[i] & (states[j]<<1))
continue ;
if(states[i] & (states[j]>>1))
continue ;
for(k = 0 ; k < states.size() ; k++){
if(states[k] & cannot[row-2])
continue ;
if(states[i] & states[k])
continue ;
if(states[j] & (states[k]<<1))
continue ;
if(states[j] & (states[k]>>1))
continue ;
if(dp[(row-1)&1][j][k] == -1)
continue ;
dp[row&1][i][j] = max(dp[row&1][i][j] ,
dp[(row-1)&1][j][k] + people[i]) ;
}
}
}
}
for(i = 0 ; i < states.size() ; i++)
for(j = 0 ; j < states.size() ; j++)
sum = max(sum , dp[N&1][i][j]) ;
return sum ;
}

int main(){
int i , j , x ;
while(cin>>N>>M){
memset(cannot , 0 , sizeof(cannot)) ;
for(i = 1 ; i <= N ; i++){
for(j = 0 ; j < M ; j++){
cin>>x ;
if(!x)
cannot[i] |= (1<<j) ;
}
}
cout<<DP()<<endl ;
}
return 0 ;
}


炮兵阵地

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 4
PHPP
PPHH
PPPP
PHPP
PHHP

Sample Output
6


int N , M ;
int dp[101][70][70] ;
int cannot[101] ;

int ok(int x){
if(x & (x<<1))
return 0 ;
if(x & (x<<2))
return 0 ;
if(x & (x>>1))
return 0 ;
if(x & (x>>2))
return 0 ;
return 1 ;
}

int Count(int x){
int sum = 0 ;
while(x){
sum += (x&1) ;
x >>= 1 ;
}
return sum ;
}

void get_all_states(vector<int> &states , vector<int> &people){
states.clear() ;
people.clear() ;
for(int i = 0 ; i < (1<<M) ; i++){
if(ok(i)){
states.push_back(i) ;
people.push_back(Count(i)) ;
}
}
}

int DP(){
int i , j , k , row , ans = 0 ;
memset(dp , 0 , sizeof(dp)) ;
vector<int> states , people ;
get_all_states(states , people) ;
for(i = 0 ; i < states.size() ; i++){
if(states[i] & cannot[1])
continue ;
dp[1][i][0] = people[i] ;
}
for(row = 2 ; row <= N ; row++){
for(i = 0 ; i < states.size() ; i++){
if(states[i] & cannot[row])
continue ;
for(j = 0 ; j < states.size() ; j++){
if(states[j] & cannot[row-1])
continue ;
if(states[i] & states[j])
continue ;
for(k = 0 ; k < states.size() ; k++){
if(states[i] & states[k])
continue ;
if(states[j] & states[k])
continue ;
if(dp[row-1][j][k] == -1)
continue ;
dp[row][i][j] = max(dp[row][i][j] ,
dp[row-1][j][k] + people[i]) ;
}
}
}
}
for(i = 0 ; i < states.size() ; i++)
for(j = 0 ; j < states.size() ; j++)
ans = max(ans , dp
[i][j]) ;
return ans ;
}

int main(){
string s ;
while(cin>>N>>M){
memset(cannot , 0 , sizeof(cannot)) ;
for(int i = 1 ; i <= N ; i++){
cin>>s ;
for(int j = 0 ; j < M ; j++){
if(s[j] == 'H')
cannot[i] |= (1<<j) ;
}
}
cout<<DP()<<endl ;
}
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: