UVA 10201 Adventures in Moving Part IV

UVA_10201

    我们不妨用f[i][j]表示到第i个加油站油量为j时这个状态所需的最小花费,那么首先有一部分状态是从第i-1个加油站继承过来的,即f[i][j]=f[i-1][j+d[i]-d[i-1]],之后就是考虑在第i个加油站买多少油会更划算,那么状态转移方程为f[i][j]=min{min{f[i][k]+(j-k)*m[i]},f[i][j]},这样乍看上去是三个for,然而对于min{f[i][k]+(j-k)*m[i]}这个部分,实际上我们也可以写成f[i][k]-k*m[i]+j*m[i],而f[i][k]-k*m[i]这个部分仅和k有关,我们可以在循环j的时候顺便记录下最小的f[i][j]-j*m[i]即可,不妨设为temp,那么第二个动态转移方程就变成了f[i][j]=min{min{temp+j*m[i]},f[i][j]}。

#include<stdio.h>
#include<string.h>
#define MAXD 110
#define MAXL 210
#define INF 1000000000
int L, N, f[MAXD][MAXL], d[MAXD], m[MAXD];
char b[100];
void init()
{
gets(b);
sscanf(b, "%d", &L);
N = 0;
d[0] = 0;
while(gets(b) != NULL)
{
if(b[0] == '\0')
break;
++ N;
sscanf(b, "%d%d", &d[N], &m[N]);
if(d[N] < 0 || d[N] > L)
-- N;
}
}
void solve()
{
int i, j, k, temp, dis;
for(i = 0; i <= N; i ++)
for(j = 0; j <= 200; j ++)
f[i][j] = INF;
f[0][100] = 0;
for(i = 1; i <= N; i ++)
{
dis = d[i] - d[i - 1];
for(j = 0; j + dis <= 200; j ++)
if(f[i - 1][j + dis] < f[i][j])
f[i][j] = f[i - 1][j + dis];
temp = INF;
for(j = 0; j <= 200; j ++)
{
if(f[i][j] - m[i] * j < temp)
temp = f[i][j] - m[i] * j;
if(temp + m[i] * j < f[i][j])
f[i][j] = temp + m[i] * j;
}
}
if(L - d[N] > 100 || f[N][100 + L - d[N]] == INF)
printf("Impossible\n");
else
printf("%d\n", f[N][100 + L - d[N]]);
}
int main()
{
int t;
gets(b);
sscanf(b, "%d", &t);
gets(b);
while(t --)
{
init();
solve();
if(t)
printf("\n");
}
return 0;
}


原文地址:https://www.cnblogs.com/staginner/p/2268942.html