首页 > 其他分享 >2022CCPC威海 D. Sternhalma(记忆化搜索/状压)

2022CCPC威海 D. Sternhalma(记忆化搜索/状压)

时间:2022-11-10 19:45:27浏览次数:50  
标签:stat Sternhalma 2022CCPC int 状压 continue nx2 && 棋子

题意大概是给定一个19个格子的六边形棋盘,每个位置有一个分数,每次操作可以拿走一个棋子(不得分)或者将当前棋子跳过相邻的一个棋子(得分为跳过的棋子所在位置的分数)且将跳过的棋子拿走,问分数最大是多少。

记忆化搜索+状压。因为只有19个位置,因此可以用一个int整数表示状态,同时注意到是一个棋盘对应多种摆放顺序,因此联想到记忆化。这个题的难点在于棋盘是六边形,枚举转移较为麻烦。

#include <bits/stdc++.h>
using namespace std;
int score[5][5], n;
int vis[(1 << 20) + 5];
int Pos[5][5] = {//Pos[i][j]表示i, j这个位置对应在状态中的下标
	{0, 1, 2},
	{3, 4, 5, 6},
	{7, 8, 9, 10, 11},
	{12, 13, 14, 15},
	{16, 17, 18},
};
int d1[5][6][2] = {//d1[i]表示第i行的位置往六个方向移动一格的坐标增量
	{
		{-1, -1}, {-1, 0}, {0, -1}, {0, 1}, {1, 0}, {1, 1},
	},
	{
		{-1, -1}, {-1, 0}, {0, -1}, {0, 1}, {1, 0}, {1, 1},
	},
	{
		{-1, -1}, {-1, 0}, {0, -1}, {0, 1}, {1, -1}, {1, 0},
	},
	{
		{-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0},
	},
	{	
		{-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0},
	}
};
int d2[5][6][2] = {//d2[i]表示第i行的位置往六个方向移动两格的坐标增量
	{
		{-2, -2}, {-2, 0}, {0, -2}, {0, 2}, {2, 0}, {2, 2},
	},
	{
		{-2, -2}, {-2, 0}, {0, -2}, {0, 2}, {2, -1}, {2, 1},
	},
	{
		{-2, -2}, {-2, 0}, {0, -2}, {0, 2}, {2, -2}, {2, 0},
	},
	{
		{-2, -1}, {-2, 1}, {0, -2}, {0, 2}, {2, -2}, {2, 0},
	},
	{	
		{-2, 0}, {-2, 2}, {0, -2}, {0, 2}, {2, -2}, {2, 0},
	}
};
int limit[5] = {2, 3, 4, 3, 2};//每行数的个数
int getStat(string s) {
	int ans = 0;
	for(int i = 0; i < s.size(); i++) {
		if(s[i] == '#') {
			ans |= (1 << i);
		}
	}
	return ans;
}
int dfs(int stat, int step) {
	if(vis[stat] != -0x3f3f3f3f) return vis[stat];
	int ans = 0;
	int mp[5][5];
	for(int i = 0; i < 5; i++) {
		for(int j = 0; j < 5; j++) {
			mp[i][j] = 0;
		}
	}
	int one = 0;
	for(int i = 0; i < 19; i++) {
		if((stat >> i) & 1) {
			//第一种操作
			one++;
			ans = max(ans, dfs(stat & (~(1 << i)), step));
			if(i >= 0 && i <= 2) {
				mp[0][i] = 1;
			} else if(i >= 3 && i <= 6) {
				mp[1][i - 3] = 1;
			} else if(i >= 7 && i <= 11) {
				mp[2][i - 7] = 1;
			} else if(i >= 12 && i <= 15) {
				mp[3][i - 12] = 1;
			} else {
				mp[4][i - 16] = 1;
			}
		}
	}
	for(int i = 0; i < 5; i++) {
		for(int j = 0; j <= limit[i]; j++) {
			if(!mp[i][j]) continue;
			int nowx = i, nowy = j;
			for(int k = 0; k < 6; k++) {
				int nx1 = nowx + d1[i][k][0], ny1 = nowy + d1[i][k][1];//要跨过的点
				int nx2 = nowx + d2[i][k][0], ny2 = nowy + d2[i][k][1];//落点
				if(nx1 < 0 || nx1 >= 5 || ny1 < 0 || ny1 > limit[nx1]) continue;//短路 所以不会出现nx1越界的情况
				if(nx2 < 0 || nx2 >= 5 || ny2 < 0 || ny2 > limit[nx2]) continue;
				if(!mp[nx1][ny1]) continue;
				if(mp[nx2][ny2]) continue;
				int nxt_stat = stat;
				nxt_stat &= (~(1 << Pos[nowx][nowy]));//构造下一个状态 首先清除当前位置
				nxt_stat &= (~(1 << Pos[nx1][ny1]));//清除跳过的位置
				nxt_stat |= (1 << (Pos[nx2][ny2]));//跳到的位置设为1
				ans = max(ans, score[nx1][ny1] + dfs(nxt_stat, step + 1));
			}
		}
	}
	vis[stat] = ans;
	return ans;
}
int main() {
	for(int i = 0; i < 5; i++) {
		for(int j = 0; j <= limit[i]; j++) {
			cin >> score[i][j];
		}
	}
	cin >> n;
	for(int i = 0; i < (1 << 20); i++) {
		vis[i] = -0x3f3f3f3f;
	}
	for(int i = 1; i <= n; i++) {
		string s = "";
		for(int j = 1; j <= 5; j++) {
			string tmp;
			cin >> tmp;
			s += tmp;
		}
		cout << dfs(getStat(s), 1) << endl;
	}
	return 0;
}

标签:stat,Sternhalma,2022CCPC,int,状压,continue,nx2,&&,棋子
From: https://www.cnblogs.com/lipoicyclic/p/16878558.html

相关文章

  • 2022CCPC威海J. Eat, Sleep, Repeat(博弈/思维)
    题目大意是给定长度为n的数组a,两个人轮流从中选一个正数将其减1。且有k个限制形如\(limit_{x_i}=y_i\),即\(x_i\)在数组中最多出现\(y_i\)次。判负的情况为:数组全为0......
  • CF1463F Max Correct Set(取小样法+状压 DP)
    CF1463FMaxCorrectSet要求选出集合\(U=\{1,2,3,\dots,n\}\)的一个子集\(S\),满足:如果\(a\inS\)并且\(b\inS\),那么\(|a-b|\not={x}\)并且\(|a-b|\not=......
  • CF1342F Make It Ascending(状压+求过程->求结果)
    CF1342FMakeItAscending给予一个包含\(n\)个元素的数组\(a\),你可以进行以下操作:选择两个不同的元素\(a_i,a_j\)(\(1\lei,j\len\),\(i\nej\))将\(a_j\)的......
  • 2022CCPC(桂林)
    我的首站本来想着练练手拿铜牌血赚打铁不亏结果保底铜牌要是G题做出来应该可以冲击一下银牌https://codeforces.com/gym/104008A.Lily签到题:所有不在L旁的字符......
  • 【CF1292F】Nora's Toy Boxes(状压DP)
    考虑将点分为$A,B$两类。其中$[x\inA]\iff\exists_{y\neqx},y|x$。那么我们删去的点只可能在$B$类中,且当前$x\inB$可删当且仅当存在$y\inB,z\inA$使得$z|x......
  • 【XSY3896】相似(dp套dp,状压)
    题面相似题解可以发现,\(S\)和\(T\)相似,等价于它们的最长公共子序列长度至少为\(n-k\)。首先考虑如何求出两个字符串的\(\text{LCS}\)(最长公共子序列)。考虑dp:......
  • 【XSY3513】Multiple of Nine(状压DP)
    题意:转化后变为:给一张\(n\)个点的图,你需要给每个点染上\([1,k]\)中的某个颜色,图上有\(m\)条边,每条边\((u,v)\)有两种边权\(w_1\)(当\(u,v\)颜色相同时)和\(w_2\)......
  • 【XSY3270】Domino Colorings(轮廓线dp,状压)
    若已经知道了每个格子的颜色,我们可以用轮廓线DP(类似插头DP)判断棋盘是否能被多米诺骨牌填满,设\(dp[S]\)表示是否存在某种填法使得轮廓线每个位置是否被填的状态为\(S\)......
  • 【XSY2444】【BZOJ4042】【CERC2014】【luogu4757】Parades(树形dp+状压dp)
    题面Description从前有个A国,它有\(n\)个城市和\(n-1\)条道路。每条路连接两个城市。城市之间两两可达。每个城市与不超过10条道路相连。现在给出\(m\)条路径,要求从这些......
  • AGC017F Zigzag【状压 DP】
    传送门以下认为\(n,m\)同阶。首先,我们可以根据每次走的方向用一个二进制数来表示一条折线。这样显然有一个傻逼DP,设\(f_{i,S}\)表示已经确定了前\(i\)条折线,其中......