【USACO2002 Feb】奶牛自行车队
-
Time Limit: 1000 ms
Memory Limit: 131072 KBytes
Description
N 头奶牛组队参加自行车赛。车队在比赛时排成一列,需要绕场S 圈。由于空气阻力的作用,领队奶牛消耗的体力要比后面的多。每头奶牛的初始体力都是相同的,记作M,体力减为负数的奶牛只能中途退赛,体力也不会在比赛途中恢复,但最后只要有一位队员到达终点就算完成了比赛。
比赛最小的单位时间是分钟。车队在每分钟必须绕赛场整数圈,最少是每分钟一圈。如果车队在一分钟里绕场x圈,领队奶牛会消耗sqr(x)点体力,跟在后面的所有奶牛将会消耗X点体力。每分钟开始的时刻,车队可以自由选择是否换下领队奶牛,让其他奶牛做领队,并且设定这一分钟的速度。如果设定该分钟的速度为x圈,则要保证领队奶牛的体力至少要大于sqr(x)。
作为它们教练,请你计划一下,应采用什么样的策略才能让车队以最快的时间完成比赛?输入数据保证 S ≤ M,因此一定存在完成比赛的方案。
Input
第一行:三个整数 N,M 和 S,1 ≤ N ≤ 20, 1 ≤ S ≤ M ≤ 100
Output
单个整数:表示最早完成比赛的时间
Sample Input
3 30 20
Sample Output
7
Hint
(时间5领队的奶牛为C)
Solution
再来写一道dp
首先设计状态
不不不,我们先来看数据范围,1≤N≤20,1≤S≤M≤100,这么小(露出邪♂恶的微笑)
那就大胆设计状态f[i][j][k]表示领头的为第i只奶牛走了j圈领头的奶牛体力剩余k的最少时间
为什么这么设计呢?
因为每头奶牛的初始体力相同,如果在最优解中该头奶牛还需继续领头则不要换奶牛
那么开始转移,这道题的转移比较绕,因为数据小方程维数多,这道题有4重循环,很难受,其实这题的转移只需分为两种状况,一种是由当前领头奶牛继续领头,另一种是由上一头奶牛换成这头奶牛
接下来挂方程:
$f\left[ i \right]\left[ j \right]\left[ k \right] = min\left\{ \begin{array}{l}f[i][j - l][k + l*l],1 < = l < = j\& \& k + l*l < = m - j + l\\f[i - 1][j - l][t],1 < = l < = j\& \& 0 < = t < = m\& \& m - j + l = = k + l{\rm{*}}l\end{array} \right.$
这里还有一个小优化(并不知道有没有用),当你处理出f[i][j][k]时,你便可以更新f[i+1][j][m-j](即换一只奶牛)
答案只需扫一遍f[i][s][k]取min即可
代码如下OwO
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 int f[25][105][105],n,m,s; 7 int main() 8 { 9 memset(f,127,sizeof(f)); 10 scanf("%d%d%d",&n,&m,&s); 11 f[1][0][m]=0; 12 for (int i=1;i<=n;i++) 13 for (int j=1;j<=s;j++) 14 for (int k=0;k<=m;k++) 15 for (int l=1;l<=j;l++){ 16 int p=pow(l,2)+k;if (p<=m-j+l){ 17 f[i][j][k]=min(f[i][j][k],f[i][j-l][p]+1); 18 f[i+1][j][m-j]=min(f[i+1][j][m-j],f[i][j][k]); 19 } 20 } 21 int ans=2147483647; 22 for (int i=1;i<=n;i++) 23 for (int k=0;k<=m;k++) ans=min(ans,f[i][s][k]); 24 printf("%d",ans); 25 return 0; 26 }