填表法与刷表法

填表法

填表法及\(f[i]\)\(f[i-1]\)等类似的已经更新过的状态转移过来一般比较习惯用填表法(比较好想)

刷表法

刷表法及用\(f[i]\)去更新\(f[i+1]\)等之后未更新完全的状态(后面的状态可能会被之前的多个状态更新)
虽然用的少但是在一些题上用刷表法会比填表法要更加方便

在状态没有明确的上界时宜用刷表

填表法eg:

状态比较好想将几个需要的状态列出来
\(i:\)选到了哪个物品(提前排好序当满足条件时当前物品的时间既是答案)
\(h:\)当前到达的高度
\(hp:\)当前所有能活到的时间
设状态:\(f[i][j]\)为选到第\(i\)个物品到达\(j\)的高度所能到达的最大hp
此题若用填表法边界情况处理起来很麻烦
尤其是在高度的那一维
因为如果高度超过\(D\)也可以出井而高度的上限就很难处理
而用刷表法当可以到达某一高度且高度大于\(D\)直接输出然后\(return\) \(0\)即可
如果到不了\(D\)前面则不会\(return\) \(0\)就直接把扔下来的垃圾全吃掉直到挺不到下一个垃圾的到来(好凄惨)

P1156 垃圾陷阱

题目描述

卡门――农夫约翰极其珍视的一条 Holsteins 奶牛――已经落了到 “垃圾井” 中。“垃圾井” 是农夫们扔垃圾的地方,它的深度为 \(D\)\(2 \le D \le 100\))英尺。

卡门想把垃圾堆起来,等到堆得高度大等于于井的深度时,她就能逃出井外了。另外,卡门可以通过吃一些垃圾来维持自己的生命。

每个垃圾都可以用来吃或堆放,并且堆放垃圾不用花费卡门的时间。

假设卡门预先知道了每个垃圾扔下的时间 \(t\)\(1 \le t \le 1000\)),以及每个垃圾堆放的高度 \(h\)\(1 \le h \le 25\))和吃进该垃圾能维持生命的时间 \(f\)\(1 \le f \le 30\)),要求出卡门最早能逃出井外的时间,假设卡门当前体内有足够持续 \(10\) 小时的能量,如果卡门 \(10\) 小时内(不含 \(10\) 小时,维持生命的时间同)没有进食,卡门就将饿死。

输入格式

第一行为两个整数,\(D\)\(G\)\(1 \le G \le 100\)),\(G\)为被投入井的垃圾的数量。

第二到第 \(G+1\) 行每行包括三个整数:\(T\)\(1 \le T \le 1000\)),表示垃圾被投进井中的时间;\(F\)\(1 \le F \le 30\)),表示该垃圾能维持卡门生命的时间;和 \(H\)\(1 \le H \le 25\)),该垃圾能垫高的高度。

输出格式

如果卡门可以爬出陷阱,输出一个整数,表示最早什么时候可以爬出;否则输出卡门最长可以存活多长时间。

样例 #1

样例输入 #1

20 4
5 4 9
9 3 2
12 6 10
13 1 1

样例输出 #1

13

提示

【样例说明】

卡门堆放她收到的第一个垃圾:\(\mathrm{height}=9\)

卡门吃掉她收到的第 \(2\) 个垃圾,使她的生命从 \(10\) 小时延伸到 \(13\) 小时;

卡门堆放第 \(3\) 个垃圾,\(\mathrm{height}=19\)

卡门堆放第 \(4\) 个垃圾,\(\mathrm{height}=20\)

std:

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int n,m;
struct A
{
	int t,g,h;
}a[N];
bool cmp(A x,A y){return x.t < y.t;}
int f[N][110]; 
int sumh;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= m;i++)scanf("%d%d%d",&a[i].t,&a[i].g,&a[i].h);
	sort(a+1,a+1+m,cmp);
	f[0][0] = 10;
	for(int i = 0;i < m;i++)
		for(int j = 0;j <= n;j++)
		{
			if(a[i+1].t <= f[i][j])//hp必须能够挺到$i+1$个垃圾扔下来
			{
				if(j+a[i+1].h >= n)return printf("%d",a[i+1].t),0;
				f[i+1][j+a[i+1].h] = max(f[i+1][j+a[i+1].h],f[i][j]);
				f[i+1][j] = max(f[i+1][j],f[i][j]+a[i+1].g);
			}	
		}
	int sum = 10;//初始值为10
	for(int i = 1;i <= m;i++)
	{
		if(sum < a[i].t)break;
		sum += a[i].g;
	}
	
	printf("%d",sum);
	return 0;
}

另一种状态

\(f[i][j]\)为选到第\(i\)个物品到达\(j\)的生命值所能到达的最大高度
\(from\) \(mhc\)

#include<bits/stdc++.h>
using namespace std;

const int N=105;
int d,n,f[N][3010];

struct T
{
	int t,life,h;
}t[N];

bool cmp(T a,T b)
{
	return a.t<b.t;
}

int main()
{
	scanf("%d%d",&d,&n);
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d",&t[i].t,&t[i].life,&t[i].h);
		sum+=t[i].life;
	}
	sort(t+1,t+1+n,cmp);
	memset(f,128,sizeof f);
	f[0][10]=0;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<=sum;j++)
		{
			if(j >= t[i+1].t)
			{
				if(f[i][j]+t[i+1].h >= d)return printf("%d",t[i+1].t),0;
				f[i+1][j+t[i+1].life] =max(f[i+1][j+t[i+1].life],f[i][j]);
				f[i+1][j] = max(f[i+1][j],f[i][j]+t[i+1].h);
			}
		}
	}
	
	sum = 10;
	for(int i = 1;i <= n;i++)
	{
		if(sum < t[i].t)break;
		sum += t[i].life;
	}
	printf("%d",sum);
	return 0;
}

一维优化(第一种状态)

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int n,m;
struct A
{
	int t,g,h;
}a[N];
bool cmp(A x,A y){return x.t < y.t;}
int f[110]; 
int sumh;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= m;i++)scanf("%d%d%d",&a[i].t,&a[i].g,&a[i].h);
	sort(a+1,a+1+m,cmp);
	f[0] = 10;
	for(int i = 0;i < m;i++)
		for(int j = n;j >= 0;j--)//倒序
		{
			if(a[i+1].t <= f[j])
			{
				if(j+a[i+1].h >= n)return printf("%d",a[i+1].t),0;
				f[j+a[i+1].h] = max(f[j+a[i+1].h],f[j]);
				f[j] = max(f[j],f[j]+a[i+1].g);
			}	
		}
	int sum = 10;
	for(int i = 1;i <= m;i++)
	{
		if(sum < a[i].t)break;
		sum += a[i].g;
	}
	
	printf("%d",sum);
	return 0;
}
posted @ 2022-10-27 21:14  AC7  阅读(400)  评论(1)    收藏  举报