1595:炮兵阵地

1595:炮兵阵地

时间限制: 1000 ms 内存限制: 524288 KB
提交数: 503 通过数: 322
【题目描述】
原题来自:NOI 2001

司令部的将军们打算在 N×M 的网格地图上部署他们的炮兵部队。一个 N×M 的地图由 N 行 M 列组成,地图的每一格可能是山地(用 H 表示),也可能是平原(用 P 表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:

如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。

现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。

【输入】
第一行包含两个由空格分割开的正整数,分别表示 N 和 M;

接下来的 N行,每一行含有连续的 M 个字符(P 或者 H),中间没有空格。按顺序表示地图中每一行的数据。

【输出】
仅一行,包含一个整数 K,表示最多能摆放的炮兵部队的数量。

【输入样例】
5 4
PHPP
PPHH
PPPP
PHPP
PHHP
【输出样例】
6
【提示】
数据范围与提示:

N≤100,M≤10。

思路:
思路很简单吧。。(但是实现非常困难qwq,作为一个不怎么细心的孩子,调了三个小时qwq)
设置变量为f[i][j][k]表示已经处理到了第i行,第i行状态是b[j],第i-1行状态是b[k]
转移方程:f[i%3][k][j]=max(f[(i-1)%3][j][l]+sum[k],f[i%3][k][j]);
注意,这里的i%3应用的是滚动数组的思想。因为对于一个状态来说,需要记录的只是与之相关的三行,其它的都可以由转移得到,所以为了减小空间复杂度,防止MLE,我们只记录三行

做题时出问题的地方:
1.dp的时候把对应的sum[k]加成了sum[j]
2.f数组开小了,最后结果爆了
3.初始化出锅

代码(已AC):

#include<bits/stdc++.h>
using namespace std;

int n,m;
char a[1050][1050];
int f[14][1050][1050];
int b[1020000];
int cnt;
int sum[102000];
int dat[102000];

int count(int x)
{
	int num=0;
	for(int i=0;i<m;i++)
	{
		if(x&(1<<i)) num++; 
	}
	return num;
}

void prepare()
{
	for(int i=0;i<(1<<m);i++)
	{
		if(!(i&(i<<1))&&!(i&(i<<2))) 
		{
			cnt++;
			b[cnt]=i;
			sum[cnt]=count(i);
		}
	}
	
//	for(int i=1;i<=cnt;i++) cout<<sum[i]<<" * ";
//	cout<<'
';
}

void dp()
{
//	for(int i=1;i<=n;i++) cout<<dat[i]<<" ";
//	cout<<'
';
	/*cout<<"f[1][i][1]: 
";*/
	for(int i=1;i<=cnt;i++)
	{
		if(!(b[i]&dat[1])) f[1][i][1]=sum[i]/*,cout<<f[1][i][1]<<" "*/;
	}
	/*cout<<'
';
	int o=0;
	cout<<"f[2][i][j]: 
";*/
	int q_sum=0;
	for(int i=1;i<=cnt;i++)
	{
		for(int j=1;j<=cnt;j++)
		{
//			cout<<i<<" "<<j<<" "<<b[i]&b[j]<<" "<<b[i]&dat[2]<<" ">>b[j]&
			if(!(b[i]&b[j])&&!(b[i]&dat[2])&&!(b[j]&dat[1]))
			{
				f[2][i][j]=sum[i]+sum[j];/*cout<<f[2][i][j]<<" "<<b[i]<<" "<<b[j]<<'
';*/
//				o++;
				q_sum=(q_sum+f[2][i][j])%100000;
			}
		}
		/*cout<<"ooooooooooooooooo "<<o<<'
';*/
//		cout<<dat[1]<<" "<<dat[2]<<" dat
";
		
	}
	/*cout<<'
';*/
	int p=0;
	
	/*for(int k=1; k<=n; k++) {
		for(int i=0; i<(1<<m); i++) {
			for(int j=0; j<(1<<m); j++)
			/*	cout<<f[k][i][j]<<" ";
			cout<<'
';
			}
		cout<<'
';
	}*/	
	
	/*for(int i=3; i<=n; i++)
		for(int L=0; L<(1<<m); L++) { //i-1
			if(L&b[i-1] || (L&(L<<1)) || (L&(L<<2))) continue;	//特判
		int q_sum=0;	for(int S=0; S<(1<<m); S++) { //i
				if(S&b[i] || L&S || (S&(S<<1)) || (S&(S<<2))) continue;
				for(int FL=0; FL<(1<<m); FL++) { //i-2
					if(FL&L || FL&S || FL&b[i-2] || (FL&(FL<<1)) || (FL&(FL<<2)))	continue;
					f[L][S][i%3]=max(f[L][S][i%3],f[FL][L][(i-1)%3]+sum[S]),		//滚动数组的实现方法
					p++;
				}
			}
		}*/
		
	
	for(int i=3;i<=n;i++)
		for(int j=1;j<=cnt;j++)//第i-1行状态
		{
			if(!(b[j]&dat[i-1]))
			for(int k=1;k<=cnt;k++)//i 
			{
				if(!(b[j]&b[k]))
				for(int l=1;l<=cnt;l++)//i-2
				{
					if(!(b[j]&b[k])&&!(b[k]&b[l])&&!(b[l]&b[j])&&!(b[k]&dat[i])&&!(b[j]&dat[i-1])&&!(b[l]&dat[i-2])) 
					{
						f[i%3][k][j]=max(f[(i-1)%3][j][l]+sum[k],f[i%3][k][j]);
//						q_sum+=f[(i-1)%3][j][l]+sum[k];
//						q_sum%=1000000;
						p++;
					}
				 } 
			}
		 } 
		 
//	cout<<p<<" pppppppppppppppp
";
//	cout<<q_sum<<" summmmmmmmmmm
";
		 
	int ans=0;
	for(int i=1;i<=cnt;i++)
		for(int j=1;j<=cnt;j++)
		{
			ans=max(ans,f[n%3][i][j]);
		}
		
	cout<<ans<<'
';
	/*for(int k=1; k<=n; k++) {
		for(int i=0; i<(1<<m); i++) {
			for(int j=0; j<(1<<m); j++)
				cout<<f[k][i][j]<<" ";
			cout<<'
';
			}
		cout<<'
';
	}	
	*/
}

int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) cin>>a[i][j];
		
	for(int i=1;i<=n;i++)
	{
		int s=0;
		for(int j=1;j<=m;j++)
		{
			if(a[i][j]=='P') 
			{
				s=(s<<1)+0;
			}
			else
			{
				s=(s<<1)+1;
			}
		}
		dat[i]=s;
	}
	
	/* for(int i=1;i<=n;i++) cout<<dat[i]<<" ";
    cout<<'
';
    cout<<"aghfukaku
";*/
	
	
	prepare();
	dp();
	return 0;
}

ps:
做题经验:
1.平常做题的时候不要和题解对代码,不要跟着题解对拍,(特别是dp类题目,对拍根本拍不出来),最好是自己从头到尾看一遍自己的代码,检查一下是不是有什么细节问题
2.跟着自己的感觉走,不要老是看题解,因为题解的方法可能很多,不一定是你的方法

ヾ(◍°∇°◍)ノ゙

原文地址:https://www.cnblogs.com/yxr001002/p/14429019.html