在这里插入图片描述
UVA1379
定义
Map[i][j]Map[i][j]为对战第ii支队伍时,胜率排名第jj位的棒球手的胜率
Schedule[i]Schedule[i]为第ii天的对手
dp[i][a][b][c][d]dp[i][a][b][c][d]为考虑到前ii天时,第ii天派出胜率排名第aa位,第i1i-1天派出第bb位,第i2i-2天派出第cc位,第i3i-3天派出第dd位选手时的最大期望值。因为选手比赛后需要ResetReset至少4天,所以需要4天的派遣情况才能去重并使状态唯一。
转移方程
if(Schedule[i])dp[i][a][b][c][d]=max(dp[i][a][b][c][d],dp[i1][b][c][d][e]+Map[Schedule[i]][a].Val)(1a,b,c,d,e5)elsedp[i][0][a][b][c]=max(dp[i1][0][a][b][c],dp[i1][a][b][c][d])(1a,b,c,d5)if(Schedule[i])\\dp[i][a][b][c][d] = max(dp[i][a][b][c][d], dp[i-1][b][c][d][e] + Map[Schedule[i]][a].Val)\\(1\leq a,b,c,d,e\leq 5)\\else\\dp[i][0][a][b][c] = max(dp[i-1][0][a][b][c], dp[i-1][a][b][c][d])\\(1\leq a,b,c,d\leq 5)
如果第ii天有比赛,则枚举第ii个人应该派遣谁,并选取由最优的子状态转移过来。(因为选手休息4天又能上场了,所以枚举到排名第5就可以了。比如选手AA第一天上场,然后第二到五天休息,第六天又能重新上场了,一到五天五个人)。如果第i天没有比赛,则以dp[i][0]dp[i][0]存储dp[i1]dp[i-1]中的最优状态。
去重
为了防止选手在5天内重复上场,在每考虑第i场比赛的人选时,要保证第i场比赛的选手在第i1i2i3i4i-1,i-2,i-3,i-4场比赛中未出场过。定义GetPitcher(Opponent,Index)GetPitcher(Opponent, Index)返回在面对编号为OpponentOpponent的对手时,排名第IndexIndex的选手的IDID。去重详见代码。
滚动数组优化
这道题的空间卡的严,如果定义dp[211][6][6][6][6]dp[211][6][6][6][6]会爆空间,因此需要优化。可以发现dpdp中不是ii就是i1i-1,明显的滚动数组优化。
AC代码

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
constexpr static int inf = 0x3f3f3f3f;
int N, M, G, D;
struct Node{
	int ID, Val;
	bool operator<(const Node& Right)const {
		return this->Val > Right.Val;
	}
}Map[101][101];
int Schedule[211];
int dp[2][6][6][6][6];
void Input() {
	scanf("%d%d%d", &N, &M, &G);
	for (int i = 1; i <= M; ++i) {
		for (int j = 1; j <= N; ++j) {
			scanf("%d", &Map[i][j].Val);
			//记录选手ID,用于去重
			Map[i][j].ID = j;
		}
		//将面对第i名对手时的选手按胜率降序排列
		sort(Map[i] + 1, Map[i] + N + 1);
	}
	D = G + 10;
	for (int i = 1; i <= D; ++i) {
		scanf("%d", &Schedule[i]);
	}
	return;
}
//如果Index是0,返回一个不存在的ID,使循环继续
int GetPitcher(int Opponent, int Index) {
	if (!Index) {
		return 0;
	}
	return Map[Opponent][Index].ID;
}
double DP() {
	memset(dp[0], 0x0, sizeof(dp[0]));
	for (int i = 1; i <= D; ++i) {
		int
			&& Cur = i & 1,//等价于i
			&& Pre = 1 - Cur;//等价于i-1

		memset(dp[Cur], 0x0, sizeof(dp[Cur]));
		if (Schedule[i]) {
			for (int a = 1; a <= 5; ++a) {
				for (int b = 0; b <= 5; ++b) {
					//如果第i场比赛派第a名选手,那就不能和第i-1场比赛时决定的第b名选手ID相同,即去重
					if (i > 1 && GetPitcher(Schedule[i], a) == GetPitcher(Schedule[i - 1], b)) {
						continue;
					}
					for (int c = 0; c <= 5; ++c) {
						if (i > 2 && GetPitcher(Schedule[i], a) == GetPitcher(Schedule[i - 2], c)) {
							continue;
						}
						for(int d = 0; d <= 5; ++d) {
							if (i > 3 && GetPitcher(Schedule[i], a) == GetPitcher(Schedule[i - 3], d)) {
								continue;
							}
							for (int e = 0; e <= 5; ++e) {
								if (i > 4 && 
									GetPitcher(Schedule[i], a) == GetPitcher(Schedule[i - 4], e)) {
									continue;
								}
								dp[Cur][a][b][c][d] = max(
									dp[Cur][a][b][c][d], 
									dp[Pre][b][c][d][e] + Map[Schedule[i]][a].Val
								);
							}
						}
					}
				}
			}
		}
		else {
			for (int a = 0; a <= 5; ++a) {
				for (int b = 0; b <= 5; ++b) {
					for (int c = 0; c <= 5; ++c) {
						for (int d = 0; d <= 5; ++d) {
							dp[Cur][0][a][b][c] = max(
								dp[Cur][0][a][b][c], 
								dp[Pre][a][b][c][d]
							);
						}
					}
				}
			}
		}
	}
	int
		&& Ans = 0, 
		&& Cur = D & 1;
	for (int a = 0; a <= 5; ++a) {
		for (int b = 0; b <= 5; ++b) {
			for (int c = 0; c <= 5; ++c) {
				for (int d = 0; d <= 5; ++d) {
					Ans = max(Ans, dp[Cur][a][b][c][d]);
				}
			}
		}
	}
	return Ans / 100.;
}
int main() {
	int T;
	cin >> T;
	while (T--) {
		Input();
		printf("%.2lf\n", DP());
	}
	return 0;
}
posted on 2020-01-23 01:36  SCU_GoodGuy  阅读(305)  评论(0)    收藏  举报