Topcoder SRM647-Div1-Lv2 CtuRobots

涉及知识点:动态规划

题意

\(n\ (\leq 500)\) 个机器人,每个机器人的价格为 \(cost_i\ (\leq 10^4)\),油箱容量为 \(cap_i\ (\leq 10^9)\),一单位燃料可以走一单位距离,你可以给购买的机器人编号,机器人 \(k\) 可以给机器人 \(k+1\) 补充燃料,但是任意时刻机器人的燃料不能超过其油箱容量上限,你有 \(B\ (\leq 10^4)\) 的预算,购买一些机器人,机器人从 \(0\) 出发,问所有机器人最终都能返回初始点的前提下,能探索到的最大距离。

思路

Tips: 题目并没有对于“速度”进行规定,也就是说,只要距离限制满足,可以视为一台机器人可以在任何时刻到某个地方,不过这个性质并不影响做题

子问题 1

假设我们已经知道了所有已经购买的机器人,如何计算能够探索的最大距离?一个显然的思路是我们只需要油箱最大的机器人进行探索任务,而其他的机器人的任务只是给它补充燃料,两个机器人同时执行探索任务只会浪费燃料没有任何好处。并且我们可以发现,对于某台负责补充燃料的机器人 \(i\),它的最佳选择是在 \(\large\frac{cap_i}{3}\) 处给下一个机器人提供燃料并返航,因为如果小于这个节点时可提供的燃料大于可被接收的燃料造成浪费,而大于这个节点自己会消耗额外的燃料。而且一个很巧妙的性质在于在 \(\large\frac{cap_i}{3}\) 处给下一个机器人补充燃料后,下一个机器人刚好回满。因此我们只需要将机器人的油箱容量从小到大排序,设 \(f_i\) 为机器人 \(i\) 的实际续航时间,有递推关系:\(\large f_1=cap_1,f_2=\frac{f_1}{3}+cap_2,\dots,f_i=\frac{f_{i-1}}{3}+cap_i\),而能探索到的最大距离便为油箱最大的机器人 \(k\) 的续航除以 \(2\)\(\large\frac{f_k}{2}\)

子问题 2

如何购买机器人使得探索距离最大?我们对于刚才的递推关系再加上预算的限制,就可以 DP 了,首先将机器人按油箱大小排序,设 \(f[i][j]\) 表示前 \(i\) 个机器人可选,预算为 \(j\) 时最大可能的续航(由于还要返程所以答案为 \(f[i][j]/2\)),每次的决策为判断是否购买第 \(i\) 个机器人。

代码

#include<bits/stdc++.h>
#define getmax(x,y) x=max(x,y)
using namespace std;
#ifdef ONLINE_JUDGE
#define getchar __getchar
inline char __getchar(){
    static char ch[1<<20],*l,*r;
    return (l==r&&(r=(l=ch)+fread(ch,1,1<<20,stdin),l==r))?EOF:*l++;
}
#endif
template<class T>inline void rd(T &x){
    T res=0,f=1;
    char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while('0'<=ch && ch<='9'){res=res*10+ch-'0';ch=getchar();}
    x=res*f;
}
typedef double db;
const db eps=1e-8;
const int MAXN=505,MAXB=1e4+5;
int n,bud;
db f[MAXN][MAXB];
struct BOT{
    int cost;
    db cap;
    bool operator < (const BOT& b){
        return cap<b.cap;
    }
}bt[MAXN];
int main(){
    rd(bud);
    rd(n);
    for(int i=1;i<=n;i++){
        rd(bt[i].cost);
    }
    rd(n);
    for(int i=1;i<=n;i++){
        rd(bt[i].cap);
    }
    sort(bt+1,bt+1+n);
    for(int i=1;i<=n;i++){
        memcpy(f[i],f[i-1],sizeof(f[i]));
        for(int j=bt[i].cost;j<=bud;j++){
            getmax(f[i][j],f[i-1][j-bt[i].cost]/3+bt[i].cap);
        }
    }
    cout<<fixed<<setprecision(8)<<f[n][bud]/2.0<<endl;
    return 0;
}
posted @ 2024-05-09 17:09  MessageBoxA  阅读(23)  评论(0)    收藏  举报