• 杭电多校第四场 1003 Contest of Rope Pulling(随机化+动态规划)


    题意:

    多组输入,给定a,b两个数组,长度分别为n,m。每个元素有两个值:wi,vi,要求从两个数组中分别选出一个子数组,使得两个子数组的wi和相同,并使总的vi之和最大。

    数据范围:n,m<=1e3,wi<=1e3,vi<=1e9,(sum(n+m)<=1e4)

    解法:

    很容易想到分别对两个数组进行背包,求出每种可能重量和的价值最大值,然后遍历两个dp数组求出价值和的最大值,复杂度为(n^2*wi),但是这样一组样例就有1e9,5组就有5e9,稳TLE了。

    首先想到将两个背包合并为一个,即对b数组的wi取反加入到a数组中,答案就是对a数组做背包后dp[0]的值。(由于数组下标不能为负,需要对每个状态加上一个base值,使所有状态对应的下标为正)。

    合并为一个背包后,可以发现最后需要的答案就是一个dp[0](为方便描述暂且不加上base值),如果对所有可能的重量的状态进行转移,会浪费掉大量对答案不一定有贡献的时间,那么如何避免这种情况呢?应该采用对合并后的a数组进行随机化的方法,基于一个随机化的数组,绝对值很大的状态再转移回dp[0]的概率是很低的,因此可以不考虑绝对值很大的状态,即减小dp数组的范围,这样答案也是有很大的几率是正确的。

    算一下时间复杂度,评测机能跑5s,就是5e8的计算量,由于总和有限制,对于n=1000,m=1000这种数据最多有5组,因此一组数据计算量是1e8,背包要做n+m次,每次计算量为5e4(但是这样可能会wa,要开大一点开1e5,评测机能3s稳过)

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll INF=1e15;
    const int maxn=2e3+5;
    const int maxdp=1e5+5;
    const int base=5e4;
    const int lim=1e5;
    pair<int,int> pi[maxn];
    void debug(ll *a,int l,int r){
        for(int i=l;i<=r;i++){
            printf("%d ",a[i]);
        }
        puts("");
    }
    ll w[maxn],v[maxn];
    ll temp[maxdp];
    ll dp[maxdp];//dp[i]:i-base重量的最大价值
    void init(){
        fill(dp,dp+maxdp,-INF);
        fill(temp,temp+maxdp,-INF);
        dp[base]=0;
        temp[base]=0;
    }
    int main () {
        srand(time(0));
        int T;
        scanf("%d",&T);
        while(T--){
            int n,m;
            scanf("%d%d",&n,&m);
            init();
            for(int i=1;i<=n+m;i++){
                scanf("%d%d",&pi[i].first,&pi[i].second);
                if(i>n){
                    pi[i].first=-pi[i].first;
                }
            }
            random_shuffle(pi+1,pi+1+n+m);
            for(int i=1;i<=n+m;i++){
                w[i]=pi[i].first;
                v[i]=pi[i].second;
            }
            for(int i=1;i<=n+m;i++){
                for(int j=min(lim,(int)lim+(int)w[i]);j-w[i]>=0;j--){
                    if(dp[j-w[i]]!=-INF){
                        temp[j]=max(dp[j],dp[j-w[i]]+v[i]);
                    }
                }
                for(int j=0;j<=maxdp-1;j++){
                    dp[j]=temp[j];
                }
            }
            printf("%lld
    ",dp[base]);
        }
    }
    
  • 相关阅读:
    Redis使用cmd进入执行命令界面
    Mime 类型列表
    BootstrapBlazor 智能生成神器(一)AutoGenerateColumnAttribute 特性介绍
    BootstrapBlazorValidateForm 表单验证组件
    RabbitMQ Windows 安装、默认设置及命令
    .Net Core 可为Null的类型
    BootstrapBlazor EditorForm 表单组件(一)
    docker 命令实录2
    win 10家庭版没有docker如何操作
    docker 记录
  • 原文地址:https://www.cnblogs.com/ucprer/p/13410423.html
Copyright © 2020-2023  润新知