UVa 10118 Free Candies

本文介绍了一种博弈问题——四堆糖果游戏的解决方案。通过动态规划的方法,利用数组记录每一步的状态并递归求解最优解。文章详细解析了算法流程,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1059


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

// record[a][b][c][d]代表第1,2,3,4堆取了a,b,c,d个糖后(位于顶部的糖果为pile[0][a+1],pile[1][b+1],pile[2][c+1], pile[3][d+1]),
// 篮子里的情况是basket[a][b][c][d]时还能取的最多糖对
int record[45][45][45][45];

// basket[a][b][c][d]代表第1,2,3,4堆取了a,b,c,d个糖后,篮子里的糖果情况,第i位代表第i种糖数量
int basket[45][45][45][45];

// pile[a][x]代表第a堆的第x个糖果的种类
int pile[4][45];

int n;

int get_max(int* now);

int main()
{
	while(scanf("%d", &n) == 1 && n != 0)
	{
		// 读入情况
		memset(record, -1, sizeof(record));
		memset(basket, 0, sizeof(basket));
	
		for(int i = 1; i <= n; i++)
			for(int j = 0; j <= 3; j++)
				scanf("%d", &pile[j][i]);
			
		// 计算结果
		int now[4];
		memset(now, 0, sizeof(now));
		printf("%d\n", get_max(now));			
	}
	return 0;
}

// 计算
// record[a][b][c][d]代表第1,2,3,4堆取了a,b,c,d个糖后(位于顶部的糖果为pile[0][a+1],pile[1][b+1],pile[2][c+1], pile[3][d+1]),
// 篮子里的情况是basket[a][b][c][d]时还能取的最多糖对
int get_max(int* now)
{
	if(record[now[0]][now[1]][now[2]][now[3]] != -1)
		return record[now[0]][now[1]][now[2]][now[3]];
	
	// 查看篮子中的糖果情况
	int b = basket[now[0]][now[1]][now[2]][now[3]];

	int candy[21];
	memset(candy, 0, sizeof(candy));
	int sum = 0;
	for(int i = 1; i <= 20; i++)
	{
		candy[21-i] = b - ((b >> 1) << 1);
		b = (b >> 1);
		sum += candy[21-i];	
	}
	if(sum >= 5)
	{
		record[now[0]][now[1]][now[2]][now[3]] = 0;
		return record[now[0]][now[1]][now[2]][now[3]];
	}
	
	// 如果篮子有空,查看四种可能的取法
	int ans = 0;
	for(int i = 0; i < 4; i++)
	{
		if(now[i]+1 > n)
			continue;
		int new_c = pile[i][now[i]+1];
		now[i]++;
		if(candy[new_c] == 0)
		{
			candy[new_c] = 1;
			int this_b = 0;
			for(int i = 1; i <= 20; i++)
				this_b = (this_b<<1) + candy[i];
			basket[now[0]][now[1]][now[2]][now[3]] = this_b;
			ans = max(ans, get_max(now));	
			candy[new_c] = 0;
		}		
		else if(candy[new_c] == 1)
		{
			candy[new_c] = 0;
			int this_b = 0;
                        for(int i = 1; i <= 20; i++)
                                this_b = (this_b<<1) + candy[i];
                        basket[now[0]][now[1]][now[2]][now[3]] = this_b;
                        ans = max(ans, get_max(now) + 1);   
                        candy[new_c] = 1;		
		}
		now[i]--;
	}		
	record[now[0]][now[1]][now[2]][now[3]] = ans;
	return record[now[0]][now[1]][now[2]][now[3]];	
}

感觉是道好题,题目状态一开始比较好想,无非是四个堆的要取的位置和篮子里的情况,篮子里的情况可以用一个整数来二进制表示。

但是即使这样,存储的数组也太大((40^4)*(2^20)). 后来没想出来,看了别人的做法,发现如果能够达到目前堆的状态,那么篮子里的情况应该是唯一的。(不知如何证明)

所以只需要保存堆的状态就可以了,用另外一个数组来记录每个堆的状态下篮子的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值