Description
Input
輸入最多包含25組測試數據。每組數據第一行爲兩個整數n和p(1<=n<=1000, 1<=p<=100),即戰鬥的場數和你的初始力量值。以下n行每行6個整數p1, p2, t1, t2, w1, w2(1<=p1<p2<=100, 1<=t2<t1<=100, 0<=w1,w2<=10),按順序給出各場戰鬥的參數。輸入結束標誌爲n=p=0。
Output
對於每組數據,輸出最短總時間(單位:秒),保留兩位小數。如果無解,輸出“Impossible”(不含引號)。
Sample Input
1 55 50 75 40 15 10 0 2 55 50 75 40 15 10 0 50 75 40 15 10 0 3 1 1 2 2 1 0 5 1 2 2 1 1 0 1 100 100 1 0 0 1 7 4 15 35 23 0 0 1 1 2 3 2 1 0 0 0 0
Sample Output
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;
}