35.00
60.00
41.00
31.73
Impossible
分析:刚开始以为是模拟,直接上测数据发现不对,后来才知道模拟搞不定,必须枚举在开始下一场战斗前吃“乘2血”的瓶数,而对于“加1血”当前有多少瓶全吃掉是最优的。
记忆化搜索
#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
const double INF=99999999.0;
int n,p;
struct node
{
int p1,p2,t1,t2,w1,w2;
}st[1100];
double dp[1100][110][15]; //dp[n][s][num] 表示进行第n-1场战斗刚结束,体力值为s,带num瓶乘2血瓶到达目标状态的最小时间
double cal(int s,int x)
{
if(s>=st[x].p2)
return st[x].t2;
double k=1.0*(st[x].t1-st[x].t2)/(st[x].p1-st[x].p2);
double b=st[x].t1-k*st[x].p1;
return 1.0*k*s+b;
}
double dfs(int x,int s,int num)
{
if(x>n)return 0;
if(dp[x][s][num]>-1)return dp[x][s][num];
while(s<st[x].p1 && num)
{
s=min(100,s*2);
num--;
}
if(s<st[x].p1)
{
dp[x][s][num]=INF;
return INF;
}
dp[x][s][num]=INF;
for(int i=0;i<=num;i++)
{
int ss=s<<i;
double t=cal(ss,x);
dp[x][s][num]=min(dp[x][s][num],t+dfs(x+1,min(100,ss+st[x].w1),min(10,num-i+st[x].w2)));
}
return dp[x][s][num];
}
int main()
{
while( cin>>n>>p )
{
if( n==0 && p==0 ) break;
for(int i=1;i<=n;i++)
scanf("%d%d%d%d%d%d",&st[i].p1,&st[i].p2,&st[i].t1,&st[i].t2,&st[i].w1,&st[i].w2);
memset(dp,-1,sizeof(dp));
double ans=dfs(1,p,0);
if(ans==INF)
printf("Impossible\n");
else
printf("%.2lf\n",ans);
}
return 0;
}