• 刷题总结——竞赛得分(ssoj)


    题目:

    题目描述

    ZZH 在经历了无数次学科竞赛的失败以后,得到了一个真理:做一题就要对一题!但是要完全正确地做对一题是要花很多时间(包括调试时间),而竞赛的时间有限。所以开始做题之前最好先认真审题,估计一下每一题如果要完全正确地做出来所需要的时间,然后选择一些有把握的题目先做。 当然,如果做完了预先选择的题目之后还有时间,但是这些时间又不足以完全解决一道题目,应该把其他的题目用贪心之类的算法随便做做,争取“骗”一点分数。根据每一题解题时间的估计值,确定一种做题方案(即哪些题目认真做,哪些题目“骗”分,哪些不做),使能在限定的时间内获得最高的得分。

    输入格式

    第一行有两个正整数 N 和 T,表示题目的总数以及竞赛的时限(单位秒)。以下的 N 行,每行 4 个正整数 W1i  、T1i 、W2i  、T2i ,分别表示第 i 题:完全正确做出来的得分、完全正确做出来所花费的时间(单位秒)、“骗”来的分数、“骗”分所花费的时间(单位秒)。

    其中,3≤N≤30,2≤T≤1080000,1≤W1i ,W2i≤30000; 1≤T1i,T2i≤T。

    输出格式

    输出所能得到的最高分值。

    样例数据 1

    输入  [复制]

     
    4 10800 
    18 3600 3 1800 
    22 4000 12 3000 
    28 6000 0 3000 
    32 8000 24 6000

    输出

    50

    样例数据 2

    输入  [复制]

     
    3 7200 
    50 5400 10 900 
    50 7200 10 900 
    50 5400 10 900

    输出

    70

    题解:

      这里引用ssoi官方题解:

      简单动态规划,二维费用背包问题,需要使用滚动数组。

      此题几乎是裸的 0/1 背包。而 0/1 背包就是一个很典型的顺序可以交换的例子。当然前提是状态是 f[i][j]代表前 i 道题用 j 的时间得到的最多的分数。这种情况下你把 i 放在外层循环或把 j 放在外层循环都是可以 AC 的。因为状态转移方程是 f[i][j]=max(f[i-1][j-cost1[i]]+score1[i],f[i-1][j-cost2[i]]+score2[i],f[i-1][j])。这样无论循环是哪个在外面,枚举到当前状态时,所需的前驱状态都已经计算出来了。

      不过特别的,对于这道题,如果采取这样的状态,空间上有些紧张。所以我们必须把 i 那一维优化掉。注意到i每次是由 i-1 转移过来的,并且前驱状态的 j 一定小于等于当前状态的 j!所以如果不设 i 那一维,把 i 放在外面循环并且 j 循环用 downto 的话,就可以保证每次转移的前驱都是 i-1 的情况。这样时间复杂度不变依然是 O(NT),但空间复杂度降到了 O(T)。这是我们对这道题的特殊之处的特殊优化,也可以说我们是对 0/1 背包的特殊之处的特殊优化。

      注意用一位数组优化!注意循环外层先枚举题目,然后注意再开两个dp数组防止枚举到同一道题正解贪心都做的情况!!

      连基本的背包dp都做不来了····

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<cctype>
    #include<string>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=35;
    const int W=1080005;
    int w1[N],v1[N],w2[N],v2[N],n,t;
    int dp[W],dp1[W],dp2[W];
    int main()
    {
      //freopen("a.in","r",stdin);
      scanf("%d%d",&n,&t);
      for(int i=1;i<=n;i++)
        scanf("%d%d%d%d",&v1[i],&w1[i],&v2[i],&w2[i]);
      for(int i=1;i<=n;i++)
      {
        for(int j=t;j>=w1[i];j--)
          dp1[j]=max(dp1[j],dp[j-w1[i]]+v1[i]);
        for(int j=t;j>=w2[i];j--)
          dp2[j]=max(dp2[j],dp[j-w2[i]]+v2[i]);
        for(int j=1;j<=t;j++)
          dp[j]=max(dp1[j],dp2[j]);
      }
      int ans=0;
      for(int j=1;j<=t;j++)
        ans=max(ans,dp[j]);
      cout<<ans<<endl;
      return 0;
    }
  • 相关阅读:
    python zip文件读取转存excel
    R语言--初步学习
    Python 设置进度条
    python简单爬虫(股票信息)
    如何将windbg设置为默认截崩溃软件
    python简单爬虫(中国大学排名)
    win10远程桌面连接提示身份验证错误怎么办?
    redis 学习
    keepalived入门
    sqlite内存数据库和文件数据库的同步[转]
  • 原文地址:https://www.cnblogs.com/AseanA/p/7388084.html
Copyright © 2020-2023  润新知