URAL 1152 False Mirrors

4 篇文章 0 订阅
1 篇文章 0 订阅

    链接: URAL  1152

    题意:有 n 个阳台(暂且这么看吧...)围成一个圆把英雄包围在中央,每个阳台有一定数量的怪物。英雄每开一炮,能摧毁相邻的 3 个阳台,使阳台上面的怪物全部灭亡,但其他阳台里每个怪物会对英雄造成 1 点伤害(强制扣血啊),英雄再发出一炮,剩下的怪物再反击一次,英雄再开一炮,剩下的怪物继续反击一次。。。直到所有怪物被消灭,问英雄最少受到多少伤害。注意,第 1 个阳台和第 n 个阳台相邻,第 2 个阳台摧毁后,第 1 个阳台和第 3 个阳台还是不相邻(只要 n 不等于 3)。

   思路:状态 DP + 记忆化搜索。第一次写,学习了。


位操作:

判断点 j 是否属于集合 i :i & (1<<j)

在集合 i 中去除点 j :i – (1<<j)  或者 i & ( ~( 1 << j ) ) 

在集合 i 中加入点 j :i | (1<<j)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

#define maxn 22
#define status 1<<21
#define INF 0x3f3f3f3f

int n,cost[maxn],dp[status];

void init()
{
	memset(dp,-1,sizeof(dp));
	dp[0] = 0;

	scanf("%d",&n);

	for(int i = 0;i < n;++i)
		cin>>cost[i];
}

//计算该状态下所剩余的怪物
int value(int state)
{
	int sum = 0;
	for(int i = 0;i < n;++i)
	{
		//判断 第 i 个阳台是否还存在
		if(state & (1<<i))
		{
			sum += cost[i];
		}
	}
	return sum;
}

int solve(int state)
{
	if(dp[state] != -1) return dp[state];

	int cur = INF,next;
	for(int i = 0;i < n;++i)
	{
		//判断第 i 个阳台是否存在
		if(state & (1<<i))
		{
			next = state;
			//打掉该阳台的相邻3个阳台进入下个状态
			next &= ~(1<<((i-1+n)%n));
			next &= ~(1<<i);
			next &= ~(1<<((i+1)%n));

			//这一步所受伤害
			cur = min(cur,value(next) + solve(next));
		}
	}

	//把最小伤害存到 dp[state]
	dp[state] = cur;
	return cur;
}

int main()
{
	init();
	int ans = solve((1<<n) - 1);
	cout<<ans<<endl;
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值