bzoj1933

此题秒一眼发现要求最值,那么能用的方法有 dp 贪心 流对于此题都是有可能的,但是感觉上dp可能性比较大因为总共的情况有3^n种,但是其中有一些不成立,不过你发现答案的最值就是2100*900这不是很大,这更印证了我们的想法,也许看到n<70发现也许是流,但是建图好像并不是很好建,所以我们dp试试。

那么现在带入dp的框架,一般的dp顺序是很重要的,你一定要考虑转移的顺序,经思考发现任意顺序都行,(先开始我怀疑有可能需要一些贪心的方法来确定顺序,这样的话 一般是假设现在我们求到了最值,那么我们改变一些书的顺序,这个书一般是相当特殊的那个也就是对你的答案影响最大的,但是观察我们要求的答案,思考无果,因为答案和很多书都有关系)所以任意顺序都行了。

这样我们设计的dp应该是dp[70][300][300][300][2100][2100][2100],这个很明显是不能过的,我们再来看看我们都用了哪些条件,发现貌似还有很多条件都没用,比如max h 以及t的和,我们只用了三层这个条件,来求最值 所以我们需要思考一下怎么用,再来看看我们现在得到了什么 我们已经知道任意顺序都是可以的,那么如何用这些条件? max h t的和 任意顺序, max h显然和顺序有极强的关系了,因为如果我们用h排序,那么max h就不变了,除非它新加进去。t的和也是一定的。

嗯,我们也许现在能设计出一个好的转移了

dp[70][2100][2100],70*2100*2100搞

先排序 然后第一层的和 第二层的和 第三层的和也知道了 用dp和这些东西 maxh也知道了,

那么可以转移了!

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct pointt
{
	int h, t;
};
pointt p[2100];
int n;
int dp[2][2200][2200];
int cnt[3],sum[80];
bool com(pointt a, pointt b)
{
	return a.h > b.h;
}
void update(int state, int kind,int lasth,int lastmax,pointt pnow)
{
	if (cnt[kind] == 0)
	{
		lasth += pnow.h;
	}
	cnt[kind] += pnow.t;
	lastmax = max(lastmax, cnt[kind]);
	dp[state][cnt[0]][cnt[1]] = min(dp[state][cnt[0]][cnt[1]], lasth*lastmax);
	cnt[kind] -= pnow.t;
}
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d%d", &p[i].h, &p[i].t);
	sort(p + 1, p + n + 1, com);
	int state = 0;
	for (int i = 1; i <= n; i++)
	{
		sum[i] = sum[i - 1] + p[i].t;
		for (int j = 0; j <= sum[i]; j++)
		{
			for (int k = 0; k <= sum[i] - j; k++)
			{
				dp[state][j][k] = 1000000000;
			}
		}
		int laststate = state ^ 1;
		for (int j = 0; j <= sum[i - 1]; j++)
		{
			for (int k = 0; k <= sum[i - 1] - j; k++)
			{
				if (dp[laststate][j][k] == 1000000000)
					continue;
				cnt[0] = j;
				cnt[1] = k;
				cnt[2] = sum[i - 1] - j - k;
				int lasth,lastmax;
				lastmax = (max(max(cnt[0], cnt[1]), cnt[2]));
				if (lastmax)
				{
					lasth = dp[laststate][j][k] / lastmax;
				}
				else
				{
					lasth = 0;
				}
				for (int pp= 0; pp < 3; pp++)
					update(state, pp, lasth, lastmax, p[i]);
			}
		}
		state ^= 1;
	}
	int ans = 1000000000;
	state ^= 1;
	for (int i = 1; i <= sum[n]; i++)
	{
		for (int j = 1; j <= sum[n] - i; j++)
		{
			int k = sum[n] - i - j;
			if (k == 0)continue;
			ans = min(ans, dp[state][i][k]);
		}
	}
	printf("%d\n", ans);

}

猜你喜欢

转载自blog.csdn.net/guoshiyuan484/article/details/81151779