动态规划求解Fire问题

这个问题其实用贪心策略更好吧,硬要用动态规划也是没有问题的。

/*
* 现在一个房子里着火了,你需要从这个房里抢救一些东西出来。
* 有n件物品,第i件物品的价值是p[i],抢救需要花费t[i]的时间,
* 如果物品超过d[i]的时间还没有被抢救出来就会被烧掉。
* 问能救出的物品价值之和最大为多少,并且输出你能抢到的物品编号。
* 这个问题看起来和活动选择问题很像,区别是这个问题的起始时间都是0。
* 设f[i][j]表示考虑到第i个物品,到j时刻为止最大能救的价值量。
* 如果不选择物品,则f[i][j]=f[i-1][j]。
* 如果选择第i件物品,那么在第i-1件物品考虑完后的时刻+t[i]=j,且j<=d[i],所以第i-1件物品考虑完后的时刻为j-t[i]
* 所以f[j]=max(f[i-1][j],f[i-1][j-t[i]]+p[i],且t[i]<=j<=d[i])。
* 这里需要以截止时间d[i]为关键字进行升序排序。(这里是一个贪心的策略,优先救取会先被烧掉的东西,这样有更多的机会去救别的东西)
*/
#include<iostream>
#include<vector>
#include<iomanip>
#include<algorithm>
using namespace std;
#define example 0
class thing
{
private:
	char ID;//物品编号
	int P;//物品价值
	int T;//物品抢救所花时间
	int D;//物品被烧毁的时刻
public:
	thing(char _ID, int _P, int _T, int _D) :ID(_ID), P(_P), T(_T), D(_D) {}
	thing(const thing& another) :ID(another.ID), P(another.P), T(another.T), D(another.D) {}
	inline char id() { return ID; }
	inline int p() { return P; }
	inline int d() { return D; }
	inline int t() { return T; }
	~thing(){}
	friend bool operator<(const thing& a, const thing& b) { return a.D < b.D; }
};

#if example==0
vector<thing> a = {
	{'A',4,3,7},
	{'B',5,2,6},
	{'C',6,3,7 }
};
#elif example==1
vector<thing>a = {
	{'A',1,5,6},
	{'B',5,3,3}
};
#endif
void show(int** r,int i, int j);
int main()
{
	sort(a.begin(), a.end(), [](const thing& a, const thing& b) {return a < b; });
	int TIME = (a.end() - 1)->d();//取最长被烧毁时刻
	int N = a.size();
	int** f = new int* [N+1];
	int** Rec = new int* [N + 1];
	for (int i = 0; i <= N; i++)
	{
		f[i] = new int[TIME + 1]{ 0 };
		Rec[i] = new int[TIME + 1]{ 0 };
	}

	for (int i = 1; i <= N; i++)
	{
		for (int j = 1; j <= TIME; j++)
		{
			if (j > a[i - 1].d())//所剩时间不够救出第i件物品,只能放弃
				f[i][j] = f[i - 1][j];
			else if (j < a[i - 1].t())//大火还没烧,没开始抢救
			{
				f[i][j] = f[i][j - 1];
				Rec[i][j] = Rec[i][j - 1];
			}
				
			else
			{
				if (f[i - 1][j - a[i - 1].t()] + a[i - 1].p() > f[i - 1][j])
				{
					f[i][j] = f[i - 1][j - a[i - 1].t()] + a[i - 1].p();
					Rec[i][j] = 1;
				}
				else
					f[i][j] = f[i - 1][j];
			}
		}
	}

	cout<<"抢救最大价值为: " << f[N][TIME] << endl;
	show(Rec, N, TIME);

	for (int i = 0; i <= N; i++)
	{
		delete[] f[i];
		delete[] Rec[i];
	}
	delete[] f;
	delete[] Rec;
	return 0;
}

void show(int** r,int i, int j)
{
	if (i == 0)
		return;
	show(r, i - 1, j - r[i][j] * a[i-1].t());
	if (r[i][j] != 0)
		cout << "选取了" << a[i - 1].id() << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值