luogu P2704【NOI2001】 & SSL1384 炮兵阵地【状压DP】

55 篇文章 0 订阅
11 篇文章 0 订阅
该博客介绍了如何利用状压DP解决NOI2001和SSL1384题目中的炮兵阵地问题。首先对地形进行预处理,然后通过枚举和动态规划求解最优方案。转移方程为f[i][l][k]=max(f[i][l][k],f[i−1][k][j]+num[l]),要考虑地形条件和放置炮兵的可行性。" 103840738,9217908,子网掩码详解与分组转发算法,"['网络技术', 'IP地址', '路由', '子网计算']
摘要由CSDN通过智能技术生成

在这里插入图片描述

状压DP

解题思路

首先对高山和平原做一个预处理
再枚举 i ( 1 , 2 < < n ) i(1,2<<n) i1,2<<n,将二进制数存在 a [ i ] a[i] a[i] 里,将兵数存在 n u m [ i ] num[i] num[i] 里。
然后开始DP
f [ i ] [ l ] [ k ] f[i][l][k] f[i][l][k] 表示当第 i i i 行有 j j j 个炮兵, i i i 的上一行有 k k k 点贡献。
转移方程
f [ i ] [ l ] [ k ] = max ⁡ ( f [ i ] [ l ] [ k ] , f [ i − 1 ] [ k ] [ j ] + n u m [ l ] ) ; f[i][l][k]=\max(f[i][l][k],f[i-1][k][j]+num[l]); f[i][l][k]=max(f[i][l][k],f[i1][k][j]+num[l]);
这里我们不仅要判断是否可放炮兵,还要判断当前位置是不是山头。

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;

int map[1010],a[1<<10],num[1<<10];
int n,m,tot,ans;
char c;

int lowbit(int x)
{
	return x&(-x);
} 
bool check(int x)
{
	int cnt=0;
	while(x)
	 {
	 	if((x&1)&&cnt)
	 	  return 0;
	 	if(x&1)
	 	  cnt=3;
	 	if(cnt)
	 	  cnt--;
	 	x>>=1;
	 }
	return 1;
}
int count(int x)
{
	int c=0;
	for(int i=x; i>0; i-=lowbit(i))
	   c++;
	return c;
}
int main()
{
    cin>>n>>m;
    for(int i=1; i<=n; i++)
     for(int j=1; j<=m; j++)
      {
      	 cin>>c;
      	 if(c=='P')
      	   map[i]=(map[i]<<1);
      	 else
      	   map[i]=(map[i]<<1)+1;
      }
    for(int i=0; i<1<<m; i++)
     {
     	if(check(i))
     	 {
     	 	a[++tot]=i;
     	 	num[tot]=count(i);
     	 }
     }
    int f[110][tot+1][tot+1];
    for(int i=1; i<=n; i++)
     for(int j=1; j<=tot; j++)
      if(!(a[j]&map[i-2]))
       for(int k=1; k<=tot; k++)
        if(!(a[j]&a[k])&&!(a[k]&map[i-1]))
         for(int l=1; l<=tot; l++)
          if(!(a[j]&a[l])&&!(a[k]&a[l])&&!(a[l]&map[i]))
           f[i][l][k]=max(f[i][l][k],f[i-1][k][j]+num[l]);
    for(int i=1; i<=tot; i++)
     for(int j=1; j<=tot; j++)
        ans=max(ans,f[n][i][j]);
    cout<<ans;
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值