一、快餐问题
1.问题引入
Peter最近在R市开了一家快餐店,为了招揽顾客,该快餐店准备推出一种套餐,该套餐由A个汉堡,B个薯条和C个饮料组成。为了提高产量,Peter从著名的麦当劳公司引进了N条生产线。所有的生产线都可以生产汉堡,薯条和饮料,由于每条生产线每天所能提供的生产时间是有限的、不同的,而汉堡,薯条和饮料的单位生产时间又不同。这使得Peter很为难,不知道如何安排生产才能使一天中生产的套餐产量最大。请你编一程序,计算一天中套餐的最大生产量。为简单起见,假设汉堡、薯条和饮料的日产量不超过100个。
输入:
输入文件共四行。第一行为三个不超过100的正整数A、B、C中间以一个空格分开。第三行为3个不超过100的正整数p1,p2,p3分别为汉堡,薯条和饮料的单位生产耗时。中间以一个空格分开。第三行为N(0<=0<=10),第四行为N个不超过10000的正整数,分别为各条生产流水线每天提供的生产时间,中间以一个空格分开。
2.思路分析
F[i,j]表示前i条生产线生产j个汉堡,k个薯条所能生产的最多饮料, 则最多套餐ans:=min{j div a,k div b,f[I,j,k] div c}
F[i,j,k]:=max{f[i-1,j',k']+(T[i]-(j-j')*p1-(k-k')*p2) div p3}
时间复杂度 O(10*100^4)
3.代码如下
二、过河
1.问题引入
在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度)。坐标为0的点表示桥的起点,坐标为L的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是S到T之间的任意正整数(包括S,T)。当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥。
题目给出独木桥的长度L,青蛙跳跃的距离范围S,T,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。
对于30%的数据,L <= 10000;
对于全部的数据,L <= 10^9。
10
2 3 5
2 3 5 6 7
2
2.思路分析
本来这道题可以说是一道简单的DP题,状态转移方程也容易找出:f [ i ] = min ( f [ i - j ] ) + stone [ i ] S <= j <=T && i >= j
但是,这道题的难点就是独木桥的长度 L 最高可达到 10^9.如果用常规方法用 for 循环从1递推到 L + T,难免会超时.
这个时候我们要用离散化思想来压缩路径.
我们会发现:
① f [ i ] 只跟 f [ (i - j)min ]~ f [ (i - j)max ] ( S <= j <= T && i >= j)有关.
② 石头的个数M远远小于L.换句话意思就是在某两个石头之间存在一大段空白,这个时候 f [ i ] 在这个区域递推值都是不变的.
由于上面的①和②我们可知在递推 f [ step ] 的时候,我们最多需要f [ step - T ]~ f [ step - S ]之间的值.这个时候我们只要第一次推出某一个 step1 位置,使得:
f [ step1 - T ]~ f [ step1 - S ] 与 f [ step - T ]~ f [ step - S ] 每个值对应相等.(如果S≠T, f [ step1 - T ]~ f [ step1 - S ] 每个值也是相等的)
剩下的从 step1 到 step就不用递推了.这里我们就达到了优化的左右,路径长度从 step 优化到 step1.
现在我们只需要找到最大的 step1,然后就可以把 L 压缩到 step1*M.
若 p*x+(p+1)*y=Q(采用跳跃距离 p 和 p+1 时可以跳至任何位置 Q),则在Q ≥ P*(P-1)时是一定有解的。
由于题目给出的一个区间是1≤S≤T≤10,于是当相邻的两个石子之间的距离不小于8*9=72时,则后面的距离都可以到达,我们就可以认为它们之间的距离就是72。如此一来,我们就将原题L的范围缩小为了100*72=7200,动态规划算法完全可以承受了。
特殊的,S=T的时候,那么上式方程无恒解,而f [ step1 - T ]~ f [ step1 - S ] 之间的每个值并不是都想等的,但 f [ step1 - T ]~ f [ step1 - S ] 与 f [ step - T ]~ f [ step - S ] 每个值对应相等.所以对于这种情况我们不能简简单单的把两个石头之间的距离压缩成72.而是还要加上除以72的余数.
压缩策略: 那么对于每两个石头之间的距离 Xi.
① 当Xi<2*72的时候,不予压缩.
②当Xi≥2*72的时候,压缩Xi=72-(Xi)%72 ;
总规模最大为:2*100*72=14400.
3.代码如下
<span style="color:#330099">package 动态规划__贪心的动态规划;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
public class 过河 {
static int L, s, t, m;
static int a[]=new int[111];
static int f[]=new int[210111];
static int dp[]=new int[210111];
public static void main(String args[]) throws IOException{
BufferedReader buf=new BufferedReader(new InputStreamReader(System.in));
String x=buf.readLine();
L=Integer.parseInt(x);
String y=buf.readLine();
String y1[]=y.split(" ");
s=Integer.parseInt(y1[0]);
t=Integer.parseInt(y1[1]);
m=Integer.parseInt(y1[2]);
String z=buf.readLine();
String z1[]=z.split(" ");
for(int i = 1; i <= m; i++)
a[i]=Integer.parseInt(z1[i-1]);
Arrays.sort(a);
a[0] = 0;
int tmp = t;
int pos = 0;
for(int i = 1; i <= m; i++)
{
int d = a[i] - a[i - 1];
if(d > 2 * tmp)
{
if(d % tmp == 0) d = tmp;
else d = d % tmp;
d += tmp;
}
pos = pos + d;
f[pos] = 1;
}
dp[0] = 0;
for(int i = 1; i <= 22222; i++) dp[i] = 1000;
int mi;
for(int i = 1; i <= pos + t; i++)
{
mi = 1000;
for(int j = i - t; j <= i - s; j++)
if(j >= 0 && dp[j] < mi)
mi = dp[j];
dp[i] = mi + f[i];
}
mi = 1000;
for (int i = pos + 1; i <= pos + t; i++)
if (dp[i] < mi)
mi = dp[i];
System.out.print(mi);
}
}</span>