社区讨论

萌新求助10分

P2704[NOI2001] 炮兵阵地参与者 2已保存回复 2

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
2 条
当前快照
1 份
快照标识符
@lo3b1f1i
此快照首次捕获于
2023/10/24 03:42
2 年前
此快照最后确认于
2023/10/24 03:42
2 年前
查看原帖
初学状压,自己想了想有思路但是只过了第一个点,大佬救救我
f[i][j][k]f[i][j][k] 存的是第 ii 行排列方式为 jj ,第 i1i-1 行排列方式为 kk ,的摆放的最大数量。
mpimp_i 存第 ii 的地图,0 表示平原,1表示山地。
gig_i 存符合炮兵攻击范围的队形。
cnticnt_i 表示 ii 的二进制的炮兵数量。
CPP
#include<bits/stdc++.h>
using namespace std;
const int N=(1<<10);
const int IM=2147483647;
const long long LLM=9223372036854775807;

inline int read()
{
	int x=0,y=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') y=-y;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^'0');c=getchar();}
	return x*y;
}

int n,m,num,g[N],mp[N],cnt[N],f[3][N][N];
string s;

signed main()
{
	n=read(),m=read();
	
	for(int i=1;i<=n;i++)//初始化存地形 
	{
		cin>>s; 
		for(int j=0;j<m;j++)
		{
			mp[i]<<=1;
			if(s[j]=='H') mp[i]++;
		}
	}
	
	for(int i=0;i<(1<<n);i++)
	{
		int p=i;
		while(p){if(p&1) cnt[i]++;p>>=1;}
		if((!(i&(i<<2)))&&(!(i&(i>>2)))&&(!(i&(i<<1)))&&(!(i&(i>>1)))) g[++num]=i;//存炮兵可能队形 
	}
	
	for(int i=1+1;i<=n+1;i++)//从第二行开始循环
	{
		for(int l=1;l<=num;l++)
		{
			int s1=g[l];
			if(s1&mp[i]) continue;//判断s1在第i行是否可行 
			for(int r=1;r<=num;r++)
			{
				int s2=g[r];
				if((s2&mp[i-1])||(s1&s2)) continue;//判断s2在第i-1行是否可行 以及s1和s2是否冲突 
				for(int k=1;k<=num;k++)
				{
					int s3=g[k];
					if((s3&mp[i-2])||(s1&s3)||(s2&s3)) continue;//同上 
					f[i%3][s1][s2]=max(f[i%3][s1][s2],f[(i-1)%3][s2][s3]+cnt[s1]);//转移 
				}
			}
		}
	}
	int ans=0;
	for(int i=1;i<=num;i++)
	{
		int s1=g[i];
		for(int j=1;j<=num;j++)
		{
			int s2=g[j];
			if(s1&s2) continue;
			ans=max(ans,f[n%3][s1][s2]);
		}
	}
	printf("%d\n",ans);
	return 0;
}

回复

2 条回复,欢迎继续交流。

正在加载回复...