棒球投手 Pitcher Rotation

在这里插入图片描述
UVA1379
定义
M a p [ i ] [ j ] Map[i][j] Map[i][j]为对战第 i i i支队伍时,胜率排名第 j j j位的棒球手的胜率
S c h e d u l e [ i ] Schedule[i] Schedule[i]为第 i i i天的对手
d p [ i ] [ a ] [ b ] [ c ] [ d ] dp[i][a][b][c][d] dp[i][a][b][c][d]为考虑到前 i i i天时,第 i i i天派出胜率排名第 a a a位,第 i − 1 i-1 i1天派出第 b b b位,第 i − 2 i-2 i2天派出第 c c c位,第 i − 3 i-3 i3天派出第 d d d位选手时的最大期望值。因为选手比赛后需要 R e s e t Reset Reset至少4天,所以需要4天的派遣情况才能去重并使状态唯一。
转移方程
i f ( S c h e d u l e [ i ] ) d p [ i ] [ a ] [ b ] [ c ] [ d ] = m a x ( d p [ i ] [ a ] [ b ] [ c ] [ d ] , d p [ i − 1 ] [ b ] [ c ] [ d ] [ e ] + M a p [ S c h e d u l e [ i ] ] [ a ] . V a l ) ( 1 ≤ a , b , c , d , e ≤ 5 ) e l s e d p [ i ] [ 0 ] [ a ] [ b ] [ c ] = m a x ( d p [ i − 1 ] [ 0 ] [ a ] [ b ] [ c ] , d p [ i − 1 ] [ a ] [ b ] [ c ] [ d ] ) ( 1 ≤ a , b , c , d ≤ 5 ) 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) 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)
如果第 i i i天有比赛,则枚举第 i i i个人应该派遣谁,并选取由最优的子状态转移过来。(因为选手休息4天又能上场了,所以枚举到排名第5就可以了。比如选手 A A A第一天上场,然后第二到五天休息,第六天又能重新上场了,一到五天五个人)。如果第i天没有比赛,则以 d p [ i ] [ 0 ] dp[i][0] dp[i][0]存储 d p [ i − 1 ] dp[i-1] dp[i1]中的最优状态。
去重
为了防止选手在5天内重复上场,在每考虑第i场比赛的人选时,要保证第i场比赛的选手在第 i − 1 , i − 2 , i − 3 , i − 4 i-1,i-2,i-3,i-4 i1i2i3i4场比赛中未出场过。定义 G e t P i t c h e r ( O p p o n e n t , I n d e x ) GetPitcher(Opponent, Index) GetPitcher(Opponent,Index)返回在面对编号为 O p p o n e n t Opponent Opponent的对手时,排名第 I n d e x Index Index的选手的 I D ID ID。去重详见代码。
滚动数组优化
这道题的空间卡的严,如果定义 d p [ 211 ] [ 6 ] [ 6 ] [ 6 ] [ 6 ] dp[211][6][6][6][6] dp[211][6][6][6][6]会爆空间,因此需要优化。可以发现 d p dp dp中不是 i i i就是 i − 1 i-1 i1,明显的滚动数组优化。
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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值