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
i−1天派出第
b
b
b位,第
i
−
2
i-2
i−2天派出第
c
c
c位,第
i
−
3
i-3
i−3天派出第
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[i−1][b][c][d][e]+Map[Schedule[i]][a].Val)(1≤a,b,c,d,e≤5)elsedp[i][0][a][b][c]=max(dp[i−1][0][a][b][c],dp[i−1][a][b][c][d])(1≤a,b,c,d≤5)
如果第
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[i−1]中的最优状态。
去重:
为了防止选手在5天内重复上场,在每考虑第i场比赛的人选时,要保证第i场比赛的选手在第
i
−
1
,
i
−
2
,
i
−
3
,
i
−
4
i-1,i-2,i-3,i-4
i−1,i−2,i−3,i−4场比赛中未出场过。定义
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
i−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;
}