51nod 1489 蜥蜴和地下室

51nod 1489


这一题这次秋招里好像有道也考到了相同的题。


题解:


dfs或是dp,思路都是相同的。  最坏情况下需要考虑遍历的状态是一样的,从而算法复杂度是一样的。


f[i][j][k]表示对前i-1个敌人直接火球攻击所需的火球攻击数,  j,k表示第i-1与i标号的敌人的生命剩余。然后进行状态转移。

遍历i,j,k状态有n*maxh*maxh种状态,而每种最多转移出maxh种状态。

因此时间复杂度为O(n*maxh^3)


AC代码:
#include<iostream>

using namespace std;

#define mylen 11
#define mylife 17
int n, a, b;
int h[mylen];
int f[mylen][mylife][mylife];

int direct_hit[mylife];
int next_hit[mylife];
int direct_hit_life[mylife];
int next_hit_life[mylife];

const int maxbound = mylife * mylen;

void init()
{
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j <= h[i-1]; ++j)
		{
			for (int k = 0; k <= h[i]; ++k)
			{
				f[i][j][k] = maxbound;
			}
		}
	}

	for (int i = 1; i <= mylife; ++i)
	{
		direct_hit[i] = (i - 1) / a + 1;
		direct_hit_life[i] = i * a;
		next_hit[i] = (i - 1) / b + 1;
		next_hit_life[i] = i * b;
		//cout << direct_hit[i] << '\t';
	}
}

void process()
{
	f[1][h[0]][h[1]] = 0;

	int min_hit, max_hit, tmp_j, tmp_k, tmp_num, i;
	for (i = 1; i < n-1; ++i)
	{
		for (int j = 0; j <= h[i - 1]; ++j)
		{
			min_hit = next_hit[j];
			for (int k = 0; k <= h[i]; ++k)
			{
				max_hit = ((direct_hit[k]>min_hit)?direct_hit[k]:min_hit);
				for (int num = min_hit; num <= max_hit; ++num)
				{
					tmp_num = f[i][j][k] + num;

					tmp_j = ((k > direct_hit_life[num]) ? (k-direct_hit_life[num]) : 0);
					tmp_k = ((h[i + 1] > next_hit_life[num]) ? (h[i + 1] - next_hit_life[num]) : 0);
					if (f[i + 1][tmp_j][tmp_k] > tmp_num)
					{
						f[i + 1][tmp_j][tmp_k] = tmp_num;
					//	cout << tmp_num << '\t';						
					}
				}
			}
		}
	}

	int result = maxbound;
	for (int j = 0; j <= h[i]; ++j)
	{
		if (result > f[i][0][j] + next_hit[j])
		{
			result = f[i][0][j] + next_hit[j];
		}
	}
/*	for (int j = 0; j <= h[n - 2]; ++j)
	{
		if (result > f[n - 1][j][0])
		{
			result = f[n - 1][j][0];
		}
	}*/

	printf("%d\n", result);

/*	cout << endl;
	for (int i = 1; i < n; ++i)
	{
		for (int j = 0; j <= h[i - 1]; ++j)
		{
			for (int k = 0; k <= h[i]; ++k)
			{
				cout << f[i][j][k] << '\t';
			}
		}
		cout << endl;
	}*/
}

int main()
{
	scanf("%d%d%d", &n, &a, &b);
	for (int i = 0; i < n; ++i)
	{
		scanf("%d", &h[i]);
		++h[i];
	}

	init();
	process();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值