*(中等)动态规划 HOJ 2508 Pitcher Rotation

Pitcher Rotation

My Tags  (Edit)
Source : kaohsiung 2006
Time limit : 10 secMemory limit : 64 M

Submitted : 72, Accepted : 41

Description

For professional baseball team managers, it is an important task to decide the starting pitcher for each game. In the information era, massive data has been collected in professional sports. The manager knows the winning percentage of each pitcher against each team. Unfortunately, when playing against a certain team you cannot always pick the pitcher with the highest winning percentage against that team because there is a rule saying that after pitching a game the pitcher has to rest for at least four days. There are npitchers (5<=n<=100) , m opponent teams (3<=m<=30) , and there are g (3<=g<=200) games in a season, and the season lasts for g+ 10 days. Furthermore, there is at most one game per day. You are given an m by n matrix P , where an element in P , pij , denote the winning percentage of pitcher j against team i , and a list of g + 10 numbers, d1d2,..., dg+10 , to represent the schedule of the team, where di denotes the opponent team and di = 0 denotes that there is no game at the i -th day of the season. Your task is to decide the starting pitcher for each game so that the expected number of winning game is maximized.

Input

The first line contains an integer t (1<=t<=5) indicating the number of teams that need your help. The data about these t teams follows. For each team, the first line contains the number of pitchers n , the number of opponent teams m , and the number of games in a season g . The next m lines contains the information about winning percentage of each pitcher against each team; the first line isp11p12,..., p1n , and the i -th line is pi1pi2,..., pin , where each pij is a two-digit number (for example, 92 represents 0.92). The nextg + 10 lines describe the schedule of the season, d1d2,..., dg+10 .

Output

The maximum value of expected game won for these t teams in the order of their appearance in the input file, output the answer for each team in separated lines.

Sample Input

1 
5 3 6
91 90 50 50 50
65 40 60 60 60
66 40 60 60 60
1 
2 
3 
3 
2 
1 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0

Sample Output

4.26

题意:有一个g+10天的比赛,你拥有n个投手,对方有m个队伍,然后每天对方队伍出场的顺序已知,你的每个投手对对方的每个队伍的胜率也已知,如果安排了一个投手上场,那么这个投手最少需要休息4天才能上场,即如果投手在x天上场了,那么他如果要再次上场,那么那个时间最早是在x+5天。然后要你求出胜利场数的最大期望。。。

思路:我自己没想出来。。。。一开始想到的是dp[滚动][i][j][k][l]  用来表示某四天的状态,但是好大啊。。。i,j,k,l都100,不管是时间还是空间都直接爆掉啊。。。后来看了题解。。。发现其实对于某一天,我们出场的投手其实是确定的,就是胜率最高的5个投手,因为即使前4名投手分配在了前四天,那么这一天肯定会取胜率第五的投手,而不会取更低的,如果胜率更高的投手没有在前四天用过,那么我们就直接就排他上场了,所以我们用dp[i][a][b][c][d]表示第i天取投手d,i-1天取投手c,i-2天取投手b,i-3天取投手a的最大期望,那么状态转移方程是dp[i][b][c][d][e] = max(dp[i][b][c][d][e],dp[i-1][a][b][c][d]+w)  其中如果某一天不用比赛,那么那个状态用0表示

(极搓无比)代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define max(a,b) (a) < (b) ? (b) : (a)
#define LL long long

int n , m , g;
int team[220];
int dp[220][10][10][10][10];
struct Pitcher
{
Pitcher(int w,int n) : win(w) , No(n) { }
int win;
int No;
};

bool cmp(const Pitcher& p1 , const Pitcher &p2)
{
if (p1.win==p2.win) return p1.No < p2.No;
return p1.win > p2.win;
}

vector<Pitcher> pp[110];
vector<Pitcher> p[220];
void init()
{
for (int i = 0 ; i <= m ; ++i) 
pp[i].clear();
for (int i = 0 ; i <= g+10 ; ++i) 
p[i].clear();
memset(dp,0,sizeof(dp));
}

void input()
{
scanf("%d%d%d",&n,&m,&g);
for (int i = 1 ; i <= m ; ++i) 
{
pp[i].push_back(Pitcher(1000,1));
for (int j = 1 ; j <= n ; ++j) 
{
int tmp;
scanf("%d",&tmp);
pp[i].push_back(Pitcher(tmp,j));
}
sort(pp[i].begin(),pp[i].end(),cmp);
}
for (int i = 1 ; i <= g+10 ; ++i)
{
scanf("%d",team+i);
p[i] = pp[team[i]];
}
}

void solve()
{
int ans = 0;
for (int i = 1 ; i <= g+10 ; ++i)
{
for (int a = 0 ; a <= 5 ; ++a)
{
if (i-4 <= 0  && a > 0) break;
if (i-4 > 0 && team[i-4]==0 && a > 0) break;
if (i-4 > 0 && team[i-4] && a==0) continue;
for (int b = 0 ; b <= 5 ; ++b)
{
if (i-3 <= 0 && b > 0) break;
if (i-3 > 0 && team[i-3]==0 && b > 0) break;
if (a && b && p[i-3][b].No==p[i-4][a].No) continue;
if (i-3 > 0 && team[i-3] && b==0) continue;
for (int c = 0 ; c <= 5 ; ++c)
{
if (i-2 <= 0 && c > 0) break;
if (i-2 > 0 && team[i-2]==0 && c > 0) break;
if (a && c && p[i-2][c].No==p[i-4][a].No) continue;
if (b && c && p[i-2][c].No==p[i-3][b].No) continue;
if (i-2 > 0 && team[i-2] && c==0) continue;
for (int d = 0 ; d <= 5 ; ++d)
{
if (i-1<=0 && d > 0) break;
if (i-1 > 0 && team[i-1]==0 && d > 0) break;
if (i-1 > 0 && team[i-1] && d==0) continue;
if (a && d && p[i-1][d].No==p[i-4][a].No) continue;
if (b && d && p[i-1][d].No==p[i-3][b].No) continue;
if (c && d && p[i-1][d].No==p[i-2][c].No) continue;
for (int e = 0 ; e <= 5 ; ++e)
{
if (team[i]==0 && e > 0) break;
if (team[i] && e==0) continue;
if (a && e && p[i][e].No==p[i-4][a].No) continue;
if (b && e && p[i][e].No==p[i-3][b].No) continue;
if (c && e && p[i][e].No==p[i-2][c].No) continue;
if (d && e && p[i][e].No==p[i-1][d].No) continue;
if (e==0) dp[i][b][c][d][e] = max(dp[i][b][c][d][e],dp[i-1][a][b][c][d]);
else dp[i][b][c][d][e] = max(dp[i][b][c][d][e],dp[i-1][a][b][c][d]+p[i][e].win);
if (dp[i][b][c][d][e] > ans)
ans = dp[i][b][c][d][e];
}
}
}
}
}
}
printf("%.2lf\n",ans/100.0);
}

int main()
{
int T;
cin>>T;
while (T--)
{
init();
input();
solve();
}
}


题后语:其实在生活中我们往往见到很多事情,它们因为其数量的缘故,关系复杂的一塌糊涂,你的直觉告诉自己很想把它们全部都联系起来,虽然如果真的能联系起来,那么事情还是能理清的,但是往往由于脑力不够而理不清也理不了。其实这些事情中,真的是所有事情都有关系吗?所有事情都要关注吗?不一定,可能只需要其中几个关键点,我们可能只需要把这些关键点的联系搞清楚,那么整个事情的调理就能理清了,事情就能解决了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值