在这里插入图片描述
UVA10118
定义
dp[a][b][c][d]dp[a][b][c][d]为第0列取了aa颗糖果,第1列bb颗,第二列cc颗,第三列dd后剩下的糖果还能最多再装进口袋多少个。那么答案就是dp[0][0][0][0]dp[0][0][0][0],即考虑所有糖果。Candies[i][j]Candies[i][j]表示第ii行第jj列的糖果颜色。
初始化
dp=1dp=-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))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)\\)
IsPair(Cow,Raw)IsPair(Cow,Raw)表示拿了Candies[Col][Raw]Candies[Col][Raw]后是否能和篮子中的糖果配对,并放入口袋中。
AC代码
代码中以Raw[0]Raw[0]表示aaRaw[1]Raw[1]表示bbRaw[2]Raw[2]表示ccRaw[3]Raw[3]表示dd,以减少代码量。采用二进制压缩的方式表示当前篮子中的糖果集合。

#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;
}
posted on 2020-01-20 14:43  SCU_GoodGuy  阅读(195)  评论(0)    收藏  举报