好吧,理解这道题目的意思确实费了我一番功夫,原来每个category的电源和灯泡之间没有一一对应关系,总之各种方面的无法理解题意。。。。好吧,直接说过程。
定义状态dp[i]表示电源电压从低到高的前i个灯泡的最小花费
那么从前i个灯泡转移到前i+1个灯泡的过程当中,我们首先注意到一个减少花费的办法是可以用第i+1种灯泡去替换前面i种灯泡中的一些。
注意:①要是第i+1种灯泡替换第j种灯泡可以减小花费,那么第j种灯泡一个都不要留,全都换成第i+1种
②替换只发生在区间[k,i]区间中,不可能有替换第k种,第k+2种类似于这样中间有孔的情况。
证明:因为i+1种不能替换第k+1种,因此第k+1比第i+1更好,因此我们可以用第k+1去替换第k种来获得更优,但是我们是计算dp[i+1],之前的都已经是最小值了不可能更小了,因此与这里的更小是矛盾的。
Tips:我这里用一个map存的电源。。一个结构体存的是灯泡,vol代表voltage电压,val代表value。num数组维护了一个前缀和,快速计算从第j~i有多少个灯泡。ans即为上面的dp。
这道题不算100道动态规划,这是我发挥失误了。。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
int n,ans[1010],k,num[1010];
map<int,int> vol;
struct Node{
int vol,val,num;
bool operator<(const Node&a)const{return vol<a.vol;}
}arr[1010];
int main(){
while(scanf("%d",&n)&&n){
for(int i=1;i<=n;++i){
scanf("%d%d%d%d",&arr[i].vol,&k,&arr[i].val,&arr[i].num);
if(vol.count(arr[i].vol))
vol[arr[i].vol]=min(vol[arr[i].vol],k);
else
vol[arr[i].vol]=k;
}
sort(arr+1,arr+n+1);
for(int i=1;i<=n;++i){
num[i]=num[i-1]+arr[i].num;
ans[i]=num[i]*arr[i].val+vol[arr[i].vol];
for(int j=1;j<i;++j)
ans[i]=min(ans[i],ans[j]+(num[i]-num[j])*arr[i].val+vol[arr[i].vol]);
}
printf("%d\n",ans[n]);
vol.clear();
}
return 0;
}