题目链接:
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)). 后来没想出来,看了别人的做法,发现如果能够达到目前堆的状态,那么篮子里的情况应该是唯一的。(不知如何证明)
所以只需要保存堆的状态就可以了,用另外一个数组来记录每个堆的状态下篮子的情况。