zoukankan      html  css  js  c++  java
  • 【bzoj1700】Problem Solving 解题 dp

    题目描述

    过去的日子里,农夫John的牛没有任何题目. 可是现在他们有题目,有很多的题目. 精确地说,他们有P (1 <= P <= 300) 道题目要做. 他们还离开了农场并且象普通人一样找到了工作. 他们的月薪是M (1 <= M <= 1000) 元. 他们的题目是一流的难题,所以他们得找帮手.帮手们不是免费的,但是他们能保证在一个月内作出任何题目.每做一道题需要两比付款, 第一笔A_i(1 <= A_i <= M) 元在做题的那一个月初支付, 第二笔B_i元(1 <= B_i <= M)在做完后的下一个月初支付. 每一个月牛们用上一个月挣的钱来付款. 牛没有任何存款意识, 所以每个月的节余都回拿用去买糖吃掉了. 因为题目是相互关连的,它们必须按大概顺序解出. 比如,题目3必须在解题目4 之前或同一个月解出. 找出牛们做完所有题目并支付完所有款项的最短月数.

    输入

    * 第一行: N 和 P

    * 第2...P+1行: 第i行包含A_i和B_i, 分别是做第i道题的欲先付款和完成付款.

    输出

    * 第一行: 牛们做完题目和付完帐目的最少月数

    样例输入

    100 5
    40 20
    60 20
    30 50
    30 50
    40 40

    样例输出

    6

    提示

     

    题解

    动态规划。

    第一眼看到这题以为是贪心,然而贪心是错误的,下面数据为反例。

    50 5  

    40 10  

    10 40  

    10 5  

    10 3  

    10 2

    于是想到动态规划。

    设f[i][j]为一次性选[i,j]之内的题,且选完后该月不选其它题的最小月数。

    那么可以推出f[j][i]=min(f[k][j-1]+2)

                  和f[j][i]=min(f[k][j-1]+1)(条件:选完[k , j-1]下个月剩余的钱足够选[j , i])

    于是用前缀和求区间和,时间复杂度压缩为O(p^3),AC

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define inf 0x3f3f3f3f
    using namespace std;
    int f[302][302] , a[302] , b[302] , suma[302] , sumb[302];
    int main()
    {
        int n , p , i , j , k , ans = inf;
        scanf("%d%d" , &n , &p);
        for(i = 2 ; i <= p + 1 ; i ++ )
        {
            scanf("%d%d" , &a[i] , &b[i]);
            suma[i] = suma[i - 1] + a[i];
            sumb[i] = sumb[i - 1] + b[i];
        }
        memset(f , 0x3f , sizeof(f));
        f[1][1] = 1;
        for(i = 2 ; i <= p + 1 ; i ++ )
        {
            for(j = 2 ; j <= i ; j ++ )
            {
                for(k = 1 ; k < j ; k ++ )
                {
                    if(f[k][j - 1] != inf && sumb[j - 1] - sumb[k - 1] <= n)
                    {
                        if(n >= suma[i] - suma[j - 1])
                            f[j][i] = min(f[j][i] , f[k][j - 1] + 2);
                        if(n - (sumb[j - 1] - sumb[k - 1]) >= suma[i] - suma[j - 1])
                            f[j][i] = min(f[j][i] , f[k][j - 1] + 1);
                    }
                }
            }
        }
        for(i = 2 ; i <= p + 1 ; i ++ )
            if(sumb[p + 1] - sumb[i - 1] <= n)
                ans = min(ans , f[i][p + 1] + 1);
        printf("%d
    " , ans);
        return 0;
    }
  • 相关阅读:
    为什么我会爱上黑客?什么才是真正的黑客
    谷歌超级机器人, 许多餐馆已经通过网络进行预订
    天呐!智能手机比任何人都更快地杀死地球
    PHP 操作结果集对象方法
    PHP 连接数据库基础操作
    PHP SESSION 操作
    PHP cookie基本操作
    PHP文件下载
    PHP文件上传案例和函数
    PHP目录操作函数汇总
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6216640.html
Copyright © 2011-2022 走看看