题目描述
卡门――农夫约翰极其珍视的一条Holsteins
奶牛――已经落了到“垃圾井”中。“垃圾井”是农夫们扔垃圾的地方,它的深度为D(2 \le D \le 100)D(2≤D≤100)英尺。
卡门想把垃圾堆起来,等到堆得与井同样高时,她就能逃出井外了。另外,卡门可以通过吃一些垃圾来维持自己的生命。
每个垃圾都可以用来吃或堆放,并且堆放垃圾不用花费卡门的时间。
假设卡门预先知道了每个垃圾扔下的时间t(0< t \le 1000)t(0<t≤1000),以及每个垃圾堆放的高度h(1 \le h \le 25h(1≤h≤25)和吃进该垃圾能维持生命的时间f(1 \le f \le 30)f(1≤f≤30),要求出卡门最早能逃出井外的时间,假设卡门当前体内有足够持续1010小时的能量,如果卡门1010小时内没有进食,卡门就将饿死。
输入输出格式
输入格式:
第一行为22个整数,DD和 G (1 \le G \le 100)G(1≤G≤100),GG为被投入井的垃圾的数量。
第二到第G+1G+1行每行包括33个整数:T (0 < T <= 1000)T(0<T<=1000),表示垃圾被投进井中的时间;F (1 \le F \le 30)F(1≤F≤30),表示该垃圾能维持卡门生命的时间;和 H (1 \le H \le 25)H(1≤H≤25),该垃圾能垫高的高度。
输出格式:
如果卡门可以爬出陷阱,输出一个整表示最早什么时候可以爬出;否则输出卡门最长可以存活多长时间。
输入输出样例
20 4 5 4 9 9 3 2 12 6 10 13 1 1
13
说明
[样例说明]
卡门堆放她收到的第一个垃圾:height=9height=9;
卡门吃掉她收到的第22个垃圾,使她的生命从1010小时延伸到1313小时;
卡门堆放第33个垃圾,height=19height=19;
卡门堆放第44个垃圾,height=20height=20。
dp不出来 参考了大佬的做法!!!!!!!!!!!
一共有四种状态: 物品 时间 生命 高度 其中物品和时间是联通的(物品要按照时间顺序排好) 所有只有三个变量
可以写二维的 也可以写成一维的滚动数组
其中这两种对时间的表达方式也有所不同
#includeusing namespace std; //input by bxd #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);i--) #define RI(n) scanf("%d",&(n)) #define RII(n,m) scanf("%d%d",&n,&m) #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k) #define RS(s) scanf("%s",s); #define LL long long #define pb push_back #define fi first #define REP(i,N) for(int i=0;i<(N);i++) #define CLR(A,v) memset(A,v,sizeof A) /// #define inf 0x3f3f3f3f #define N 300+5 struct node { int life,high; int t; }s[N]; int f[N];//前i个物品 j高度的最大血量 bool cmp(node a,node b) { return a.t<b.t; } int main() { int d,n; RII(d,n); rep(i,1,n) { RIII(s[i].t,s[i].life,s[i].high); } f[0]=10; sort(s+1,s+1+n,cmp); rep(i,1,n) repp(j,d,0) if(f[j]>=s[i].t) { if(j+s[i].high>=d) { cout<<s[i].t; return 0; } f[j+s[i].high]=max(f[j+s[i].high],f[j]); f[j]+=s[i].life; } cout< 0]; return 0; }
先尝试dp[i][j]dp[i][j]代表前i件物品处理后在j血量时达到的最大高度。
值得一提的是,j血量表示奶牛在暂时不考虑时间时所得到的最大血量
试着写一下它的状态转移方程
dp[i][j]=max(dp[i-1][j]+trash[i].h,dp[i-1][j+trash[i].c])dp[i][j]=max(dp[i−1][j]+trash[i].h,dp[i−1][j+trash[i].c])
发现这是对的,然而我们再想想,在关于j的一重循环里面,对j的取值我们似乎并不好判断,甚至要枚举很大。
所以我们再尝试讨论dp[i][j]dp[i][j]代表前i件物品处理后在h高度时达到的最大血量。
状态转移
dp[i][j]=max(dp[i-1][j]+trash[i].c,dp[i-1][j-trash[i].h])dp[i][j]=max(dp[i−1][j]+trash[i].c,dp[i−1][j−trash[i].h])
发现这样也是对的,而且j枚举起来也比较方便,于是我们选择这种算法。
总之因为高度比血量更小 所以枚举高度
#include#include using namespace std; #define maxn 1001 #define INF 0x7f7f7f7f #define max(x,y) x>y?x:y int f[101][1001]; struct arr { int x,t,h; }a[maxn]; int cmp(arr a,arr b) { return a.x<b.x; } int main() { int n,m; scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { scanf("%d%d%d",&a[i].x,&a[i].t,&a[i].h); } sort(a+1,a+m+1,cmp); for (int i=0;i<=m;i++) for (int j=0;j<=n;j++) f[i][j]=-INF; f[0][0]=10; a[0].x=a[0].t=a[0].h=0; int fl=0; for (int i=1;i<=m;i++) { for (int j=0;j<=n;j++) { if (f[i-1][j]-a[i].x+a[i-1].x>=0) { f[i][j]=max(f[i][j],f[i-1][j]-a[i].x+a[i-1].x+a[i].t); } if (f[i-1][j-a[i].h]-a[i].x+a[i-1].x>=0&&j-a[i].h>=0) { f[i][j]=max(f[i][j],f[i-1][j-a[i].h]-a[i].x+a[i-1].x); if (j==n) { printf("%d\n",a[i].x); fl=1; return 0; } } } } int ans=0; if (!fl) { for (int i=0;i<=m;i++) for (int j=0;j<=n;j++) if (f[i][j]!=INF) ans=max(ans,f[i][j]+a[i].x); printf("%d\n",ans); } }