题意:
给你一个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; }