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;
    }
  • 相关阅读:
    Two Sum II
    Subarray Sum
    Intersection of Two Arrays
    Reorder List
    Convert Sorted List to Binary Search Tree
    Remove Duplicates from Sorted List II
    Partition List
    Linked List Cycle II
    Sort List
    struts2结果跳转和参数获取
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6216640.html
Copyright © 2011-2022 走看看