记录编号 124253 评测结果 AAAAAAAAAA
题目名称 [NOI 2001]炮兵阵地 最终得分 100
用户昵称 Gravatar乌龙猹 是否通过 通过
代码语言 C++ 运行时间 0.153 s
提交时间 2014-10-02 20:32:52 内存使用 1.79 MiB
显示代码纯文本
#include<cstdio>
#include<iostream>
using namespace std;
int m,n,sum=0;
int v[101][61]={0};//v[i][j]存第i行,第j种状态;v[i][0]存第i行状态总数;
int dx[101][61]={0};//dx[i][j]与v[i][j]相对应,表示i行,第j种状态能放几个炮兵;
int fr[101][61][61]={0};//fr[i][m][n]表示前i行,第i行状态为n,第i-1行状态为m的最优解;
bool f[101][11]={0};//初始状态;
void dfs(int,int,int,int);
int main()
{
	freopen("cannon.in","r",stdin);
	freopen("cannon.out","w",stdout);
	scanf("%d%d",&m,&n);
	for(int i=1;i<=m;i++)
	{
		char x;
		for(int j=1;j<=n;j++)
		{
			cin>>x;
			if(x=='P') f[i][j]=1;
		}
	}
	for(int i=1;i<=m;i++) dfs(i,1,0,0);
	for(int i=1;i<=v[1][0];i++)//因为炮兵的影响范围是两个格,所以要先对前两行进行预处理;
	{
		for(int j=1;j<=v[2][0];j++)
		{
			if(v[1][i]&v[2][j])	continue;//表示两行状态矛盾,炮兵可以互相攻击到;
			fr[2][i][j]=dx[1][i]+dx[2][j];
		}
	}
	for(int i=3;i<=m;i++)
	{
		for(int j=1;j<=v[i][0];j++)//枚举第i行状态;
		{
			for(int p=1;p<=v[i-1][0];p++)//枚举第i-1行状态;
			{
				if(v[i][j]&v[i-1][p]) continue;//i行与i-1行不能矛盾;
				for(int q=1;q<=v[i-2][0];q++)//枚举第i-2行状态;
				{
					if(v[i][j]&v[i-2][q]||v[i-1][p]&v[i-2][q]) continue;
					if(fr[i-1][q][p]+dx[i][j]>fr[i][p][j])//前i-1行能放炮兵的数目加上第i行某个状态能放炮兵的数目;
						fr[i][p][j]=fr[i-1][q][p]+dx[i][j];//比原来大就更新;
				}
			}
		}
	}
	for(int i=1;i<=v[m-1][0];i++)//寻找后两行最优解的最大值;
	{
		for(int j=1;j<=v[m][0];j++)
		{
			if(fr[m][i][j]>sum) sum=fr[m][i][j];
		}
	}
	if(m==1)//如果数据只有一行,那么上面的语句都不会执行,需要特殊判断;
	{
		for(int i=1;i<=dx[1][0];++i)
		{
			if(dx[1][i]>sum) sum=dx[1][i];
		}
	}
	printf("%d",sum);
	return 0;
}
void dfs(int i,int j,int k,int w)//第i行第j列,状态为w,炮兵数为k;
{
	if(j>n)
	{
		v[i][++v[i][0]]=w;
		dx[i][++dx[i][0]]=k;
		return;
	}
	dfs(i,j+1,k,w);//默认不放炮兵;
	if(f[i][j]) dfs(i,j+3,k+1,w|1<<(n-j));//放置炮兵,隔开两个格放置下一个;
}