题目大意:有M(1<=M<=100)个物品要买,在市场上有N(1<=N<=100000)个物品卖,要按列表顺序买齐这M个物品,并且这N个物品在街道上也是有顺序的,求最小花费是多少。
用d[i][j]表示当前买了列表的前i个物品并且走完了街道的前j个摊子的最小花费,那么分两种情况,如果第j个摊子卖的和在列表上第i个商品相同,那么可能从d[i-1][j-1]推来或d[i][j-1],即第j个摊子买或不买,若第j个摊子卖的不是列表上的第i个商品,那么就直接由d[i][j-1]推来。
程序中用滚动数组从而在空间上压缩了一维状态。
状态转移方程:
d[i][j]=d[i][j-1](a[i].num!=b[j].num)
d[i][j]=max { d[i-1][j-1]+b[j].pri,d[i][j-1] }(a[i].num==b[j].num)
#include<cstdio> #include<vector> using namespace std; int a[110]; int b[100010]; double c[100010]; double d[110]; vector<int> G[100010]; int main(void) { int i,j,v,p,n,m; double q; scanf("%d%d",&n,&m); while((n!=0)||(m!=0)) { for(i=1;i<=n;i++) { scanf("%d",&a[i]); } for(i=1;i<=n;i++) { G[a[i]].push_back(i); } for(i=1;i<=m;i++) { scanf("%d%lf",&b[i],&c[i]); } d[0]=0; for(j=1;j<=n;j++) { d[j]=-10000; } for(i=1;i<=m;i++) { p=G[b[i]].size(); if(p!=0) { for(j=p-1;j>=0;j--) { v=G[b[i]][j]; q=-10000; if((int)(1000*d[v-1])>=0) { q=d[v-1]+c[i]; } if((int)(1000*q)>=0) { if((int)(1000*d[v])<0) { d[v]=q; } else if(q<d[v]) { d[v]=q; } } } } } if((int)(1000*d[n])<0) { printf("Impossible\n"); } else { printf("%.2f\n",d[n]); } for(i=1;i<=n;i++) { G[a[i]].clear(); } scanf("%d%d",&n,&m); } return 0; }
时间: 2024-10-14 05:11:30