您的位置:首页 > 其它

hiho一下 第139周 买零食 动态规划

2017-03-02 17:11 239 查看
原题:http://hihocoder.com/contest/hiho139/problem/1

看了下,通过率还挺高的。主要是数据量不大100,套三个循环纯暴力理论上应该都可以过的,不过时间复杂度比较高。

不过第一反应是动态规划。

价格小数部分只有0或者0.5,预处理下乘以2,转成整数类型会好算点。额外+0.5再转成int的是题主担心浮点数转换有精度损失。

dp[i][j][k] 可以表示前i个物品中,选了k个物品,和的个位数为j,时候的渴望度。初始时dp[x][0][0]为0,其他为不可能情况,可以初始为一个负数。当dp[i-1][j][k]为可能情况时候,状态转移方程为dp[i][(j+a[i])%10][k+1] = max(dp[i][(j+a[i])%10][k+1] , dp[i][j][k]+b[i])。这时的空间复杂度还比较高,考虑到当前的商品选不选之与上一个状态有关,跟之前的状态无直接关系,可以用滚动数组,减少一个维度。当用滚动数组的时候,要考虑遍历顺序,题主前几次提交都没过,后面发现是遍历顺序错了。遍历状态要从k往下递减,避免选第i个物品的结果之间相互干扰,确保当前使用的值是上一个选择第i-1个物品状态的值。

代码如下

#include<bits/stdc++.h>
using namespace std;
const int maxn = 106;
int a[maxn], b[maxn];
int dp[11][4];
inline void up(int &a, int b){if(a<b) a=b;}
int main(){
ios_base::sync_with_stdio(false);
int t;
cin>>t;
while(t--){
int n;
cin>>n;
double c;
for(int i=0; i<n; i++){
cin>>c>>b[i];
a[i] = (int)(c*2 + 0.5);
}
memset(dp, 0xff, sizeof dp);
dp[0][0]=0;
for(int i=0; i<n; i++){
for(int k=2; k>=0; k--){ //k从上往下遍历,避免这次i的结果间相互干扰,保证i对后面每个转移用到的都是i-1的结果
for(int j=0; j<10; j++){
if(dp[j][k]>=0){
int rem = (j+a[i])%10;
up(dp[rem][k+1], dp[j][k]+b[i]);
}
}
}
}
int ans=0;
for(int i=0; i<=3; i++){
up(ans, dp[0][i]);
}
cout << ans << "\n";
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: