帘卷风落窗边红,艳阳苦笑憔悴绿。
查看原帖
帘卷风落窗边红,艳阳苦笑憔悴绿。
658786
STUDENT00楼主2024/5/7 18:29

悬关!

春景

AC on 1,2,9,11,12

WA on 3,4,5,6,7,8,10

思路:

预处理出每行里,满足行的条件的炮兵布置方案。

然后状压 DP,fi,j,kf_{i,j,k} 表示第 ii 行状态为 jj,第 i−1i-1 行状态为 kk 的前 ii 行能布置的最多炮兵数。

转移时,枚举第 i−2i-2 行状态 ll,判断 i&ji\&j,i&ki\&k,j&kj\&k 是否均 00。

代码里有详细注释:

#include<bits/stdc++.h>
using namespace std;
int n,m;
char mp[105][10];
int cp[105][105],ct[105];
int f[105][105][105];
int cm(int i,int j){
	for(int k=0;k<m;k++){
		if(((j>>k)&1)&&mp[i][k]=='H') return 1; //山里不能放炮兵 
	}
	return 0;
}
int popcount(int x){
	int res=0;
	for(;x;x&=(x-1)) res++;
	return res;
} //统计 x 里 1 的个数 
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%s",mp[i]);
	for(int i=1;i<=n;i++){
		for(int j=0;j<(1<<m);j++){
			if(!((j&(j>>1))||(j&(j>>2))||cm(i,j))) cp[i][ct[i]++]=j; //预处理第 i 行满足条件的炮兵放置方案 
		}
	}
	cp[0][ct[0]++]=0; //第 0 行的特殊待遇 
	for(int j=0;j<ct[1];j++) f[1][cp[1][j]][0]=popcount(cp[1][j]); //DP 边界 
	for(int i=2;i<=n;i++){
		for(int j=0;j<ct[i];j++){
			for(int k=0;k<ct[i-1];k++){
				if(cp[i][j]&cp[i-1][k]) continue;
				for(int l=0;l<ct[i-2];l++){
					if((cp[i][j]&cp[i-2][l])||(cp[i-1][k]&cp[i-2][l])) continue;
					f[i][cp[i][j]][cp[i-1][k]]=max(f[i][cp[i][j]][cp[i-1][k]],f[i-1][cp[i-1][k]][cp[i-2][l]]+popcount(cp[i][j])); //DP 转移 
				}
			}
		}
	}
	int ans=0;
	for(int j=0;j<ct[n];j++) for(int k=0;k<ct[n-1];k++){
		if(!(cp[n][j]&cp[n-1][k])) ans=max(ans,f[n][cp[n][j]][cp[n-1][k]]); //百里挑一 
	}
	printf("%d",ans); //输出答案 
	return 0;
}
2024/5/7 18:29
加载中...