资源分配类动态规划-NOIP2018动态规划专题复习

Posted 信息学竞赛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了资源分配类动态规划-NOIP2018动态规划专题复习相关的知识,希望对你有一定的参考价值。

点击上面微信号关注我关注我哟 定期推送帐号信息学新闻竞赛自主招生信息学专业知识信息学疑难解答信息学训练营信息等诸多优质内容的微信平台,欢迎分享文章给你的朋友或者朋友圈!

资源分配类动态规划-NOIP2018动态规划专题复习

    NOIP历年考试中动态规划都是一个非常重要的考点。今天为大家带来常考的动态规划题型及知识点介绍。欢迎大家补充讨论。

除了以上描述以外,在NOIP中经常出现的动态规划类问题。今天我们介绍下

资源分配类动态规划

如果同学们有更多关于动态规划类习题的解题经验及知识点补充,欢迎在文章底部留言给我们。

机器分配问题

描述

总公司拥有高效生产设备M台,准备分给下属的N个公司。各分公司若获得这些设备,可以为国家提供一定的盈利。

  问:

  如何分配这M台设备才能使国家得到的盈利最大?求出最大盈利值。其中M<=15,N<=10。分配原则:每个公司有权获得任意数目的设备,但总台数不得超过总设备数M。

  数据文件格式为:第一行保存两个数,第一个数是设备台数M,第二个数是分公司数N。接下来是一个M*N的矩阵,表明了第I个公司分配J台机器的盈利。

  如令M=8,N=4

  矩阵为

1 3 5 7 7 10 11 11
2 2 4 5 6 8 9 12
1 4 4 6 8 8 12 15
3 4 5 6 7 8 9 11

用P(i,j)表示 j台设备分配给(如果把这个“前”字去掉下面状态转移方程就很难理解了)i个子公司的盈利最大的情形,上述的矩阵为table[M+1][N+1],为描述和编码方便,从[1][1]开始存值

要求资源分配的最大值,我们可以用二维数组f[i][j]来表示前i个公司得到j台机器后所得到的最大盈利值。

方程是:

f[i][j]=max(f[i][j],f[i-1][k]+a[i][j-k]);


我们要去枚举每一个i和j,因此用双重循环来解决,k表示第i个公司取的不取机器数,即1~i-1个公司取的机器数;f[i-1][k]表示前i-1个公司取k台机器的最大值,a[i][j-k]表示第i个公司取剩余的k台机器的利益,那么f[i-1][k]+a[i][j-k]表示的就是第i个公司不取k台机器所得到的最大值,当然,k也是用循环来枚举的。


其中,k就是划分的阶段,来进行枚举不用的机器

--------------------- 

快餐问题:

题目描述 Description 

Peter最近在R市开了一家快餐店,为了招揽顾客,该快餐店准备推出一种套餐,该套餐由A个汉堡,B个薯条和C个饮料组成。价格便宜。为了提高产量,Peter从著名的麦当劳公司引进了N条生产线。所有的生产线都可以生产汉堡、薯条和饮料,由于每条生产线每天所能提供的生产时间是有限的、不同的,而汉堡、薯条和饮料的单位生产时间又不同,这使得Peter很为难,不知道如何安排生产才能使一天中生产的套餐产量最大。请你编写程序,计算一天中套餐的最大生产量。为简单起见,假设汉堡、薯条和饮料的日产量不超过100个。


输入描述 Input Description 

第一行为三个不超过100的正整数A、B、C,中间以一个空格分开;


第二行为三个不超过100的正整数p1、p2、p3分别为汉堡、薯条和饮料的单位生产耗时。中间以一个空格分开。


第三行为一个整数N(0≤N≤10)代表流水线;


第四行为M个不超过10000的正整数,分别为各条生产流水线每天提供的生产时间,中间以一个空格分开。


输出描述 Output Description 

输出文件仅一行,即每天套餐的最大产量。


样例输入 Sample Input 

1 2 1 

1 2 1 

16 16 8 9 14


样例输出 Sample Output 

10

--------------------- 

资源分配类动态规划-NOIP2018动态规划专题复习

资源分配类动态规划-NOIP2018动态规划专题复习

资源分配类动态规划-NOIP2018动态规划专题复习


商店购物

商店中每种商品都有标价。例如,一朵花的价格是2元。一个花瓶的价格是5 元。为了 

吸引顾客,商店提供了一组优惠商品价。优惠商品是把一种或多种商品分成一组,并降价销 

售。例如,3朵花的价格不是6元而是5元。2 个花瓶加1 朵花的优惠价是10 元。试设计一 个算法,计算出某一顾客所购商品应付的最少费用。 

编程任务: 

对于给定欲购商品的价格和数量,以及优惠商品价,编程计算所购商品应付的最少费用。

Input 

由文件input.txt提供欲购商品数据。文件的第1行中有1 个整数B(0≤B≤5),表示所 

购商品种类数。接下来的B 行,每行有3 个数C,K 和P。C 表示商品的编码(每种商品有 唯一编码),1≤C≤999。K 表示购买该种商品总数,1≤K≤5。P 是该种商品的正常单价(每 件商品的价格),1≤P≤999。请注意,一次最多可购买5*5=25件商品。 

由文件offer.txt提供优惠商品价数据。文件的第1行中有1 个整数S(0≤S≤99),表示 

共有S 种优惠商品组合。接下来的S 行,每行的第一个数描述优惠商品组合中商品的种类数 j。接着是j 个数字对(C,K),其中C 是商品编码,1≤C≤999。K 表示该种商品在此组合 中的数量,1≤K≤5。每行最后一个数字P(1≤ P≤9999)表示此商品组合的优惠价。

 

Output 

程序运行结束时,将计算出的所购商品应付的最少费用输出到文件output.txt中。

 

Sample Input 

 

input.txt

 

2

 

7 3 2

 

8 2 5

 

offer.txt

 

2

 

1 7 3 5

 

2 7 1 8 2 10

 

Sample Output 

 

14

解析:

本题应该采用动态规划的方法进行设计,定义本题的最优子结构以及状态为一个五元组:dp[x1][x2][x3][x4][x5],其中x1代表要买的第一种物品的个数,x2代表要买的第二种物品的个数、以此类推。由于题目保证了B<=5,因此5元组绝对够用。


我们用一个std::vector来存储每套组合方案的捆绑的种类以及该种类需要购买的数量。


下面我们假定,不需要的物品一个都不能买,需要的物品也不能够多买。


要列出该5元组的状态转移方程,其中优惠集合记为S。


.


在代码实现的时候采用了备忘录技术。


代码表示:

--------------------- 

#include <iostream>

#include <vector>

#include <algorithm>

using namespace std;

typedef pair<int, int> P;

const int MAX       = 6;

const int INF  = 1e9;

int          map[1000];

int          n, m;

int          ids[MAX];

int          price[MAX];

int          nums[MAX];

vector<P>     pairs[100];

int          pP[100];

int          pcnt = 0;

int          dp[MAX][MAX][MAX][MAX][MAX];

int          times = 0;

int dfs( int* x )

{

       times++;

       int r = dp[x[0]][x[1]][x[2]][x[3]][x[4]];

       if ( r > 0 )

       {

              return(r);

       }

       if ( x[0] == 0 && x[1] == 0 && x[2] == 0 && x[3] == 0 && x[4] == 0 )

       {

              return(0);

       }

       int minf = INF;

       for ( int i = 0; i < pcnt; i++ )

       {

              vector<P> & vec  = pairs[i];

              int          f      = 1;

              int          *y    = new int[5];

              for ( int t = 0; t < 5; t++ )

                     y[t] = 0;

              for ( auto p : vec )

              {

                     int   id    = map[p.first];

                     int   num = p.second;

                     if ( x[id] < num )

                     {

                            f = 0; break;

                     }

                     y[id] = -num;

              }

              if ( !f )

                     continue;

              for ( int k = 0; k < 5; k++ )

                     y[k] += x[k];

              minf = min( minf, pP[i] + dfs( y ) );

       }

       int s = 0;

       for ( int i = 0; i < 5; i++ )

       {

              s += x[i] * price[i];

       }

       minf = min( minf, s );

       return(dp[x[0]][x[1]][x[2]][x[3]][x[4]] = minf);

}

 

 

int main()

{

       cin >> n;

       for ( int i = 0; i < n; i++ )

       {

              int C, K, PP;

              cin >> C >> K >> PP;

              ids[i]              = C;

              nums[i]          = K;

              price[i]    = PP;

              if ( !map[C] )

              {

                     map[C] = i;

              }

       }

       cin >> m;

       for ( int i = 0; i < m; i++ )

       {

              int          k; cin >> k;

              vector<P>     v;

              int          f = 1;

              for ( int j = 0; j < k; j++ )

              {

                     int a, b; cin >> a >> b;

                     v.push_back( make_pair( a, b ) );

              }

              int PP;

              cin >> PP;

              if ( f )

              {

                     pairs[pcnt]     = v;

                     pP[pcnt++]    = PP;

              }

       }

       cout << "答案:" << dfs( nums ) << endl;

       cout << "运行次数:" << times << endl;

       return(0);

}




其他:

修理马棚(序列分组DP)

题目描述


每天,小明和他的马外出,然后他们一边跑一边玩耍。当他们结束的时候,必须带所有的马返回马棚,小明有K个马棚。他把他的马排成一排然后跟随它走向马棚,因为他们非常疲劳,小明不想让他的马做过多的移动。因此他想了一个办法:将马按照顺序放在马棚中,后面的马放的马棚的序号不会大于前面的马放的马棚的序号。而且,他不想他的K个马棚中任何一个空置,也不想任何一匹马在外面。已知共有黑、白两种马,而且它们相处得并不十分融洽。如果有i个白马和j个黑马在一个马棚中,那么这个马棚的不愉快系数将是i*j。所有k个马棚不愉快系数的和就是系数总和。现在请你确定一种方法把n匹马放入k个马棚,使得系数总和最小 。


输入格式

在第一行有两个数字:n(1≤n≤500)和 k(1≤k≤n)。在接下来的n行是n个数。在这些行中的第i行代表队列中的第i匹马的颜色:1意味着马是黑色的,0意味着马是白色的。

输出格式

只输出一个单一的数字,代表系数总和达到的最小值。

样例输入

6 3
1
1
0
1
0
1



样例输出

2



数据范围

1≤n≤500,1≤k≤n

----------------------------------------------------------

题目分析

比较像分组背包,先用前缀和优化预处理组权值再dp

状态转移方程:设f[i][j]为前i个马棚放下j匹马能得到的最小不愉快系数,那么f[i][j]=min{f[i-1][k-1](i-1个马棚放前k-1匹马)+a[k][j](i个马棚放[k,j]内的马) | 1≤k≤j }

边界:f[0][0]=0,f[i][j]=inf | i!=0 && j!=0

时间复杂度O(n^3)


NOIP2019冬令营筹备中,欢迎咨询!


往期精选内容

(点击标题即可查看)





(1)

(2)

(3)


1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

17.

18.

19.

20.



(9)


关注「信息学竞赛」

看更多信息学趣闻与知识

↓↓


以上是关于资源分配类动态规划-NOIP2018动态规划专题复习的主要内容,如果未能解决你的问题,请参考以下文章

动态规划复习(持续更新)

NOIP训练营动态规划内部训练题!

[动态规划] 最长有效括号

动态规划入门专题合集

Leetcode之动态规划(DP)专题-474. 一和零(Ones and Zeroes)

算法面试专题-动态规划