免费糖果 Free Candies

UVA10118
定义
d p [ a ] [ b ] [ c ] [ d ] dp[a][b][c][d] 为第0列取了 a a 颗糖果,第1列 b b 颗,第二列 c c 颗,第三列 d d 后剩下的糖果还能最多再装进口袋多少个。那么答案就是 d p [ 0 ] [ 0 ] [ 0 ] [ 0 ] dp[0][0][0][0] ,即考虑所有糖果。 C a n d i e s [ i ] [ j ] Candies[i][j] 表示第 i i 行第 j j 列的糖果颜色。
初始化
d p = 1 dp=-1
表示未计算过
转移方程
d p [ a ] [ b ] [ c ] [ d ] = m a x ( d p [ a + 1 ] [ b ] [ c ] [ d ] + I s P a i r ( 0 , a + 1 ) , d p [ a ] [ b + 1 ] [ c ] [ d ] + I s P a i r ( 1 , b + 1 ) , d p [ a ] [ b ] [ c + 1 ] [ d ] + I s P a i r ( 2 , c + 1 ) , d p [ a ] [ b ] [ c ] [ d + 1 ] + I s P a i r ( 3 , d + 1 ) ) dp[a][b][c][d]=max(\\dp[a+1][b][c][d]+IsPair(0,a+1),\\dp[a][b+1][c][d]+IsPair(1,b+1),\\dp[a][b][c+1][d]+IsPair(2,c+1),\\dp[a][b][c][d+1]+IsPair(3,d+1)\\)
I s P a i r ( C o w , R a w ) IsPair(Cow,Raw) 表示拿了 C a n d i e s [ C o l ] [ R a w ] Candies[Col][Raw] 后是否能和篮子中的糖果配对,并放入口袋中。
AC代码
代码中以 R a w [ 0 ] Raw[0] 表示 a a R a w [ 1 ] Raw[1] 表示 b b R a w [ 2 ] Raw[2] 表示 c c R a w [ 3 ] Raw[3] 表示 d d ,以减少代码量。采用二进制压缩的方式表示当前篮子中的糖果集合。

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
#define scanf scanf_s
int N;
int Candies[41][4];
int dp[41][41][41][41];
bool Input() {
	cin >> N; 
	if (!N) {
		return false;
	}
	for (int i = 1; i <= N; ++i) {
		for (int j = 0; j < 4; ++j) {
			cin >> Candies[i][j];
		}
	}
	return true;
}
//获取篮子中糖果的数量
int getNumber(int CandiesSet) {
	int&& Number = 0;
	while (CandiesSet) {
		Number += (CandiesSet & 1);
		CandiesSet >>= 1;
	}
	return Number;
}
int DP(int Raw[4], int CandiesSet/*篮子中糖果的集合*/) {
	int& Ans = dp[Raw[0]][Raw[1]][Raw[2]][Raw[3]];
	//如果计算过就直接返回
	if (~Ans) {
		return Ans;
	}
	//糖果数量大于4就说明篮子满了,返回极小值
	if (getNumber(CandiesSet) > 4) {
		return Ans = 0xcfcfcfcf;
	}
	//最少装0个
	Ans = 0;
	//枚举a+1,b+1,c+1,d+1
	for (int i = 0; i < 4; ++i) {
		//如果到了最后一列最跳过,不能再往下了
		if (Raw[i] != N) {
			int&& Total = 0;
			//+1
			++Raw[i];
			//向下取的那个糖果
			int&& CurrentCandy = 1 << (Candies[Raw[i]][i] - 1);
			//如果新取的糖果再篮子集合中,则可以配对
			if (CandiesSet & CurrentCandy) {
				++Total;
			}
			//往下DP
			Total += DP(
				Raw,
				//如果新取的糖果在篮子中,就配对成功,集合去点这种糖果,如果没有,就将糖果加入篮子中(异或的开关性)
				CandiesSet ^ CurrentCandy
			);
			//还原Raw[i],为枚举下一列做准备
			--Raw[i];
			Ans = max(Ans, Total);
		}
	}
	return Ans;
}
int main() {
	ios::sync_with_stdio(false);
	while (Input()) {
		memset(dp, -1, sizeof(dp));
		int Raw[4] = { 0,0,0,0 };
		cout << DP(Raw, 0) << endl;
	}
	return 0;
}
发布了29 篇原创文章 · 获赞 32 · 访问量 9930

猜你喜欢

转载自blog.csdn.net/qq_42971794/article/details/104051088