poj1185 状态dp

本文介绍了一个关于炮兵放置的问题,并提供了一段详细的代码实现。该问题通过动态规划的方法解决炮兵在棋盘上放置时避免互相攻击的情况,寻找最多能放置多少炮兵的最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:略。

代码中有些简短注释。

#include <iostream>
using namespace std;

int dp[105][65][65]; //dp[i][k][j]存储的值为当第i-1行为k状态,第i行为j状态时可放炮兵的最大数量
int state[65], sum[65];
int map[105];
int cnt, row, col;
#define max(a, b) a>b?a:b
bool judge(int stt)
{
    if(stt & (stt<<1)) return false; //若一个放炮兵的情况的二进制序列中相邻的位同时为1,则不合理
	if(stt & (stt<<2)) return false; //若一个放炮兵的情况的二进制序列中相隔1位的位同时为1,则不合理
	return true;   
}

int getSum(int stt)
{     
    int sum = 0;

    for(int i = 0; i < col; i++)
		if((1<<i)&stt) sum++;  //计算某一种情况的二进制序列中1的个数,即放的炮兵的人数
    return sum;
}

void makeState()  
{
	for(int i = 0; i < (1<<col); i++)     //每一个i的二进制序列即为一个放炮兵的情况,1为放炮兵,0为不放
       if(judge(i))  //判断每一个放炮兵的情况是否合理
	   {
          state[cnt] = i;
		  sum[cnt++] = getSum(i);
	   }
}

int main()
{
   int i, j, k, l;
   char ch;

   memset(map, 0, sizeof(map));
   scanf("%d%d", &row, &col);
   memset(dp, -1, sizeof(dp));
   getchar();
   for(i = 0; i < row; i++)
   {
	   for(j = 0; j < col; j++)
	   {
		   scanf("%c", &ch);
		   if(ch == 'H')
			   map[i] |= (1<<j); // map存储每一行的状态,即将P当成0,H当成1进行二进制存储
	   }
	   getchar(); //因为getchar又调试了好久。。。
   }
   cnt = 0;
   makeState();
   
   for(i = 0; i < cnt; i++)   //矩阵第1行特殊处理
	   if(!(state[i]&map[0]))
		   dp[0][0][i] = sum[i];
   int ans = 0, tmp;
   for(i = 1; i < row; i++)  //从第二行开始遍历
	   for(j = 0; j < cnt; j++) //遍历所有放炮兵的合理的状态
	   {
		   if(state[j]&map[i]) continue;  //若第i行不可能取到第j种放炮兵的状态,j++
		   for(k = 0; k < cnt; k++) //遍历第i-1行的状态
		   {
               if(state[j]&state[k]) continue; //若i-1行与i行有炮兵互相攻击,k++
			   for(l = 0; l < cnt; l++) //遍历第i-2行的状态
			   {
				   if(state[j]&state[l] || dp[i-1][l][k] == -1) continue; 
				   /*dp[i-1][l][k] == -1, 用于判断i-2行的l状态和i-1行的k状态
				     对于map[i-2]和map[i-1]的情况是否是可以取到的,若dp[i-1][l][k] == -1,
					 说明是目前l,k两种状态时不可能取到的(表达得不是很清楚,我悲催的语言表达)
				   */
				   tmp = dp[i-1][l][k]+sum[j];
				   if(dp[i][k][j] < tmp)
					   dp[i][k][j] = tmp;
			   } 
		   }
	   }

	//这样写可以处理边界问题,我曾经想就在上面的四重循环中记录
    // 最大值来得到ans,但是当row为1时,不会进行上面的四重循环
   for(i = 0; i < cnt; i++) 
	   for(j = 0; j < cnt; j++)
		   if(ans < dp[row-1][i][j])
			   ans = dp[row-1][i][j];
   printf("%d\n", ans);
   //system("pause");
   return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值