题意:
给你一个x,y 给你三十个操作,每种操作的花费为c[i],求x变成y所需的最小花费和最小花费下的操作次数
方法:
我最开始以后变成i的花费dp[i]= dp[i-j] + j变成i的花费, 后面wa很多次了之后才发现j不一定比i小
因为有个操作是*0,递推的时候是从x递推到y,没有经过x变成0,0变成y, 所以这个操作会使得递推时出现错误;
除去这个操作之外的所以操作都不会是的i变小
所以我们只要算出x-y的解 和(x-0)操作+ 0-y操作的解,取最优的解即可
代码:
#include <cstdio>
#include <cstring>
#define maxn 111111
#define LL long long
int A[33];
LL dp[maxn], d[maxn];
int deal(int x, int t)
{
if(t<= 10)
return x*10+(t-1);
else if(t<= 20)
return x+(t-11);
else
return x*(t-21);
}
int main()
{
// freopen("C:\\Users\\Monkey\\Desktop\\in.txt","r",stdin);
// freopen("C:\\Users\\Monkey\\Desktop\\out1.txt","w",stdout);
int T= 0;
int x, y;
while(scanf("%d %d",&x,&y)!=EOF)
{
T++;
for(int i= 1; i<= 30; i++)
scanf("%d",&A[i]);
memset(dp, -1, sizeof(dp));
memset(d, 0, sizeof(d));
dp[x]= 0;
//printf("%d\n",deal(12,1));
for(int i= x; i<= y; i++)
if(dp[i]!= -1)
for(int j= 1; j<= 30; j++)
{
//printf()
int k= deal(i, j);
if(k<= y)
{
if(dp[k]== -1)
{
dp[k]= dp[i]+ A[j];
d[k]= d[i] +1;
}
else
{
if(dp[i]+ A[j]< dp[k])
{
dp[k]= dp[i]+ A[j];
d[k]= d[i] +1;
}
else if(dp[i] + A[j]== dp[k])
{
if(d[i]+1< d[k])
d[k]= d[i]+ 1;
}
}
}
}
LL ans1= dp[y], anst1= d[y];
// x-y的所需花费
memset(dp, -1, sizeof(dp));
memset(d, 0, sizeof(d));
dp[0]= 0;
for(int i= 0; i<= y; i++)
if(dp[i]!= -1)
for(int j= 1; j<= 30; j++)
{
//printf()
int k= deal(i, j);
if(k<= y)
{
if(dp[k]== -1)
{
dp[k]= dp[i]+ A[j];
d[k]= d[i] +1;
}
else
{
if(dp[i]+ A[j]< dp[k])
{
dp[k]= dp[i]+ A[j];
d[k]= d[i] +1;
}
else if(dp[i] + A[j]== dp[k])
{
if(d[i]+1< d[k])
d[k]= d[i]+ 1;
}
}
}
}
LL ans2= dp[y] + A[21], anst2= d[y]+1;
//x-0然后再0-y 的所需花费
LL ans, anst;
if(ans1> ans2)
ans= ans2, anst= anst2;
else if(ans1< ans2)
ans= ans1, anst= anst1;
else
{
ans= ans1;
anst= anst1< anst2? anst1: anst2;
}
printf("Case %d: %lld %lld\n",T,ans, anst);
}
return 0;
}