资源分配类动态规划-NOIP2018动态规划专题复习
Posted 信息学竞赛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了资源分配类动态规划-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
5
16 16 8 9 14
样例输出 Sample Output
10
---------------------
商店购物
商店中每种商品都有标价。例如,一朵花的价格是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冬令营筹备中,欢迎咨询!
往期精选内容
(点击标题即可查看)
(2)
(3)
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
(9)
关注「信息学竞赛」
看更多信息学趣闻与知识
↓↓↓
以上是关于资源分配类动态规划-NOIP2018动态规划专题复习的主要内容,如果未能解决你的问题,请参考以下文章