T1:
Birthday
内存限制 256MB 时间限制 1S
程序文件名 birthday.pas/birthday.c/birthday.cpp
输入文件 birthday.in 输出文件 birthday.out
前些天是 Miss D 生日,gnaw 去逛街给 Miss D 买礼物。商店有这样的福利:第 i 件商品价值为 Wi,买 k 个(k>0),可以送 Ai × k + Bi 颗 Miss D 喜欢的糖 最大预算为 M 元,最多能赚取多少糖呢?
输入
第一行两个整数 N ,M 表示礼物数和最大预算 之后 N 行,表示每件物品的 W A B
输出 一个整数 表示最多能赚取的糖数
样例输入
2 100
10 2 1
20 1 1
样例输出
21
数据范围
30%:
1 ≤ M ≤ 100
1 ≤ N ≤ 100
100%:
1 ≤ M ≤ 2000
1 ≤ N ≤ 1000
0 ≤ Ai, Bi ≤ 2000
1 ≤ Wi ≤ 2000
题解:当发现不是正常的背包模型时,我们可以考虑直接线性dp
定义:f [ i ] [ j ]:前i种物品体积为j
初始化:f [ 0 ][ 0 ]=0;
转移:也是考虑选与不选嘛(才由前面的状态转移过来)
当不选的时候就直接像背包一样(直接将前一种状态赋给后面)f [i][j]=f[i-1][j];
再考虑选的情况:考虑有什么区别(第一次选的时候加的是a+b,多次选就直接加a)
枚举种类再枚举件数:
第一次选:f[i] [j-w[i]]=max(f[i-1][j]+a[i]+b[i],f[i][j-w[i]])
第二次选:f[i][j-w[i]]=max(f[i][j]+a[i],f[i][j-w[i]])
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define N 1002 #define M 2005 ll f[N][M]; int w[N],b[N],a[N]; int read() { int sum=0,p=1;char c=getchar(); while(c<'0'||c>'9') { if(c=='-') p=-1; c=getchar(); } while(c>='0'&&c<='9') { sum=sum*10+c-'0'; c=getchar(); } return sum*p; } int main() { freopen("birthday.in","r",stdin); freopen("birthday.out","w",stdout); int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { w[i]=read(),a[i]=read(),b[i]=read(); } f[0][0]=0; for(int i=1;i<=n;i++)//不要被背包蒙蔽,就题分析题,就是普通线性dp,f[i][j]-i为前i选了j个 { for(int j=m;j>=0;j--) f[i][j]=f[i-1][j];//不选的情况 for(int j=m;j>=w[i];j--)//这一步只是在枚举体积而已 { f[i][j-w[i]]=max(f[i][j-w[i]],f[i-1][j]+a[i]+b[i]); f[i][j-w[i]]=max(f[i][j-w[i]],f[i][j]+a[i]); //由前面的转移过来 } } ll maxx=0; for(int i=0;i<=m;i++) { maxx=max(f[n][i],maxx); } printf("%lld ",maxx); } /* 2 150 20 2 3 35 5 2 */ /* 2 40 5 2 3 9 5 2 */
T2告诉我们打状压的时候要注意!!!!!
1.位运算符一定要打括号 先算术运算,后移位运算,最后位运算。
2.数组的大小一定要谨慎设置
T3:
Miss D 给 gnaw 准备了 n*m 个问题(比如 miss D 最近在追什么电视剧),并让 gnaw 从中选出一个矩形的区域,这个区域中的问题 gnaw 都能答对。Gnaw 只想知道,这个矩形最大面积是多少? 输入
n m
之后 n 行 每行有 m 个数据。
1 表示这个问题 gnaw 会做,0 表示这个问题不会做。 输出 一个数 表示最大全 1 矩形的问题数
样例输入
4 4
0 0 0 0
0 1 1 0
0 1 1 0
0 0 0 0
样例输出
4
50% 1<=n,m<=100
100% 1<=n,m<=1000
题解:
就是裸的最大子矩阵问题:
考虑使用悬线法:
h(i,j)i,j 的最大高度 r(i,j) i , j 的右边最近的障碍 l(i,j)i , j的左边最近障碍
基本思路对于每个固定的h去更新找 l , r 然后用(r-l+1)* h来更新答案
对于有向图的dp为啥要先topo:如果我们用代码实现这个过程,如何确定dp的顺序?
很显然,一个点的d值能够被确定,其先决条件是它的所有入点的d值都已被确定。因此我们需要确定一个点的排列,使得每个点的所有入点都在这个点之前出现。这里用到拓扑排序。拓扑序就是我们的顺序
还有就是这道题也可以用最长路来求,设置一个超级源点和超级汇点,求超级源点的最长路 d [ ed ] 既是答案