Ural 1223.Chernobyl’ Eagle on a Roof

  題目的大意是有x(1<=x<=1000)個強度相同的蛋,有一座有y(1<=y<=1000)層的樓,蛋的強度爲E(0<=E<=y),在i層把蛋扔下樓,若E<i則蛋碎一地,否則不會碎,可以繼續用於實驗。要求求解在最壞的情況下至少需要扔多少次才能確定蛋的強度。

 很裸的動歸題,最容易想的就是開個二維數組,dp[x][y]表示用x個蛋在y層樓高的樓測試最壞情況下至少需要

dp[x][y]次測試。狀態轉移是如果在第i層扔蛋,碎的話說明E<i,變成求1+dp[x-1][i-1],否則E>=i,變成求

1+dp[x][y-i],由於是最壞情況,所以取兩者的較大者作爲在第i層扔蛋所需的測試總數,由於要求最小值,那就對每層都做同樣的計算取最小者。這裏使用記憶化搜索會比較簡便。

 但是第一個案例就TLE了,原因是這是O(n^3)的算法,1000的3次方肯定超時。然後這時發現,因爲假設情況最壞,所以每次測試縮小的範圍都會儘可能小,那麼要最快測試完就是二分地測試,1000至多需要10次就能結束,所以當蛋數目超過10跟只有10個的結果是一樣的,所以開的dp數組可以縮小至11*1001,在記憶化搜索中當y>10時返回y=10的結果即可。這就把複雜度壓縮到O(n^2).

#include <iostream>
#include <cstring>
using namespace std;
int dp[15][1001];
int d(int a, int b)
{
	if (a > 11)
		return d(11, b);
	if (dp[a][b] != -1)
		return dp[a][b];
	if (a == 1)
		return dp[a][b] = b;
	if (b == 0)
		return dp[a][b] = 0;

	for (int i = 1;i <= b;i++)
	{
		int temp = 1 + d(a - 1, i - 1) > 1 + d(a, b - i) ? 1 + d(a - 1, i - 1) : 1 + d(a, b - i);
		if (dp[a][b] == -1 || dp[a][b] > temp)
			dp[a][b] = temp;
	}
	return dp[a][b];
}
int main()
{
	memset(dp, -1, sizeof(dp));
	while (1)
	{
		int a, b;
		cin >> a >> b;
		if (a == 0 && b == 0)
			break;
		cout << d(a, b) << endl;
	}
}


發佈了35 篇原創文章 · 獲贊 19 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章