【SCAU新生赛 9513】 防空洞 背包问题 DP

Description
有一天,dragon123偷偷地拿锄头在学校里挖开了一个尘封已久的防空洞。
他在这个防空洞里面找到许多贵重的东西:一些石头和一些液体。
dragon123知道,只要他把这些石头和液体拿出去卖,那么就一定可以赚大钱。但是,他只有一个载重量为W的瓶子来装这些东西。
防空洞里面有很多块石头,每块石头的重量为Wi,价值为Mi,但是石头不能够砸烂,否则就不值钱了。
此外,洞里面很多种贵重的液体。对于某种液体,洞内存储了Wi重量,且这Wi重量液体的总价值为Mi。
液体是可以部分放进瓶子里面的。也就是说,如果洞里面有Wi重量的某种液体,那么dragon123可以带走Ws(0<=Ws<=Wi)重量。
给出洞里面石头和液体的信息,以及瓶子的载重量W,dragon123希望你帮忙计算出他能够带回东西的最大价值。

输入格式
输入文件的第一行是n与W。
n是洞里面贵重物品的数量总和(包括石头与液体)。W是瓶子的载重量。N (1 <= N <= 100) 且 W (0 <= W <= 50000)
接下来有n行,每行都有3个数字a,b,c。
如果c是0,那么就意味着这一行表示的物品是石头。那么a就是这块石头的重量,b就是这块石头的价值。
如果c是1,那么就意味着这一行表示的物品是液体。那么a就是这种液体在山洞中的总储量,b就是山洞中所有的这种液体的总价值。

输出格式
输出仅有一行,表示能够获得的最大价值。保留小数点后两位小数。

输入样例
3 150
100 100 0
100 100 0
130 10 1

输出样例
103.85

题意:如题

思路:

可以确定是背包问题:
首先从液体入手,因为可以拿出任意数量的Wi,那么就摆脱了背包的限制(只能取整数),我们只用按照“性价比”填液体即可。也就是初始化dp数组的时候,我们只考虑装液体时,它的最优解肯定是把性价比最大的先装进去,再装次大的,以此类推(按照单位重量的价值大小从大到小塞进去)。

其次就是石头了,那么他就是一个简单的01背包问题。取or不取,状态转移方程:
dp[j] = max(dp[j], dp[j - d[i].w] + d[i].val);
最后注意一下这个石头是一个一个的,第i个石头只有一个。所以是有限数量的背包问题,内层倒序遍历。

AC代码:

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include <queue>
#include<sstream>
#include <stack>
#include <set>
#include <bitset>
#include<vector>
#define FAST ios::sync_with_stdio(false)
#define abs(a) ((a)>=0?(a):-(a))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
const int maxn = 1e5+200;
const int inf=0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1.0);
const int mod = 1e9+7;
inline int lowbit(int x){return x&(-x);}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){d=a,x=1,y=0;}else{ex_gcd(b,a%b,d,y,x);y-=x*(a/b);}}//x=(x%(b/d)+(b/d))%(b/d);
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll inv(ll x,ll p){return qpow(x,p-2,p);}
inline ll Jos(ll n,ll k,ll s=1){ll res=0;rep(i,1,n+1) res=(res+k)%i;return (res+s)%n;}
inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'|ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0',  ch = getchar();return x*f; }
int dir[4][2] = { {1,0}, {-1,0},{0,1},{0,-1} };

double dp[maxn];

typedef struct Information
{
    double w;
    double val;
    int flag;
}I;
I d[maxn];
ll n, m;

bool cmp(I a, I b)
{
    return (a.val / a.w ) > (b.val / b.w);
}

void init()
{
    ll cur = 1;
    rep(i,1,n)
    {
        if(cur > m) break;
        if(d[i].flag==0) continue;
        ll to = min(d[i].w+cur-1 ,m);
        rep(j,cur,to) dp[j] = dp[j-1] + (d[i].val / d[i].w);
        cur = to+1;
    }
}

int main()
{
    while(~scanf("%lld%lld",&n,&m))
    {
        mem(dp,0);
        rep(i,1,n)
        {
            ll a = read(), b = read(), c = read();
            d[i].w = a, d[i].val = b ;
            d[i].flag = c;
        }
        sort(d+1,d+1+n,cmp);
        init(); double ans = 0;
        rep(i,1,n) if(!d[i].flag) per(j,m,d[i].w) dp[j] = max(dp[j], dp[j - (int)d[i].w] + d[i].val);
        printf("%.2f\n",dp[m]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45492531/article/details/107750896