首先,这道题在训练时,状态转移方程写错了一点,导致一直不能算出结果出来,托了队友的后腿了。
首先,用dp[j]表示第j只船过到对岸所用的最少时间,用pay[j]表示第j只船过了对岸的最少次数,
那么状态转移方程dp[j] = min(max(dp[k]+t,a[j])+t) j-sum<=k<j
第j只船的最优解可以由它前面的j-sum只船的状态的最优解转移过来的。
#include<iostream>
using namespace std;
int a[1500];
int dp[1500];
int pay[1500];
int max(int a,int b)
{
if(a>b)
return a;
else return b;
}
int min(int a,int b)
{
if(a<b)
return a;
else return b;
}
int main()
{
int n,tmp,i,j,k;
int sum,time,test;
scanf("%d",&n);
for(i = 1;i <= n;i++)
{
memset(dp,0xFF,sizeof(dp));
memset(pay,0,sizeof(pay));
scanf("%d%d%d",&sum,&time,&test);
for(j = 1;j <= test;j++)
{
scanf("%d",&a[j]);
}
dp[0] = -time;
dp[1] = a[1] + time;
pay[1] = 1;
for(j = 1;j <= test;j++)
{
//dp[i] = min(max(dp[j]+t,a[i])+t) i-sum<=j<i
for(k = max(0,j-sum);k < j;k++)
{
tmp = max(dp[k]+time,a[j]) + time;//因为k是从-1开始的,所以应该先把j船到达原岸的
//最大时间取出来(这时j船有两个状态,j是可以从j-1从对岸过来的,也可以是j处于原地不懂),这是为什么要取max呢?因为
//如果dp[k]+time比a[j]大的话,那么肯定不能从k+1这个位置走,因为此时后面的车还没到呢。这一步需要好好理解。
if(dp[j] == -1)
{
dp[j] = tmp;
pay[j] = pay[k] + 1;
continue;
}
if(tmp < dp[j])
{
dp[j] = tmp;
pay[j] = pay[k] + 1;
}
if(dp[j] == tmp && pay[k]+1 < pay[k])
{
pay[j] = pay[k]+1;
}
}
}
printf("%d %d\n",dp[test],pay[test]);
}
return 0;
}