2018年东北地区赛S - Problem I. Spell Boost HDU - 6508

2018年东北地区赛S - Problem I. Spell Boost HDU - 6508

题目地址:https://vjudge.net/problem/HDU-6508

思路:
给一些卡,分为四种卡。
1.白卡(没效果)
2.魔法,作用卡(会对作用卡的费用减少,也会被魔法卡作用)
3.作用卡(会被魔法卡作用使其费用减少)
4.魔法卡(会对作用卡的费用减少)
有一个想法:如果我们得到最大的攻击力,其中会用到魔法卡和作用卡或者两者效果都有的卡的话,魔法卡其实是越早用越好,而作用卡越晚用晚用越好,因为作用卡会被魔法卡影响,使其费用减少,而且费用少的卡需要先使用,才能尝试更多的可能,如果一张卡是10w,一张卡是1w,为了尝试更多可能,先让费用少的先尝试,让费用多的之后对dp[N][N]进行比较。
那么,dp[N][N],第一个维度为费用值,第二个维度为用了几张魔法卡,维护的是最大攻击力。
然后就是一个01背包问题,当然为了实现我们的想法,需要对结构体进行某些特定的排序。

#include<iostream>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i = (j); i <= (k); i++)
#define per(i,j,k) for(int i = (j); i >= (k); i--)

const int N = 510;
int dp[N][N];

struct node{
	int w, x;
	int is_m, is_s;

	bool friend operator < (node a, node b){
		if (a.is_m != b.is_m) return a.is_m > b.is_m;//魔法卡先返回
		else if (a.is_s != b.is_s) return a.is_s < b.is_s;//作用卡越晚用越好

		return a.w < b.w;//先用费用小的,使其dp可以得到全部可能
	}
};

node arr[N];

void init(int x){
//	rep(i, 0, x)rep(j, 0, x) dp[i][j] = 0;
	memset(dp, 0, sizeof(dp));
}

int main(){

	ios::sync_with_stdio(false);
	cin.tie(0);

	int n, W;
	while (cin >> n >> W){

		int m_num = 0;

		rep(i, 1, n){
			cin >> arr[i].w >> arr[i].x >> arr[i].is_m >> arr[i].is_s;
			if (arr[i].is_m) ++m_num;//统计魔法卡数量
		}

		init(n);

		sort(arr + 1, arr + 1 + n);

		bool is_s = false;//判断是不是作用卡
		//从大到小遍历,可以不影响之前的状态
		rep(i, 1, n){
			if (arr[i].is_m){

				per(k, i, 1){//魔法卡从多到少
					per(j, W, 0){//费用从多到少

						int tmp_w = 0;
						if (arr[i].is_s){//有被作用效果
							is_s = true;
							tmp_w = max(0, arr[i].w - (k - 1));//触发魔法卡效果
						}
						//对于k张魔法卡,之前只有k-1张魔法卡,假如一张魔法卡去更新dp,所以被作用时
						//应该是魔法卡数量-1的费用减少
						if (is_s && tmp_w <= j){//是作用卡,费用足够
							dp[j][k] = max(dp[j][k],dp[j - tmp_w][k - 1] + arr[i].x);
						}
						else if (!is_s && arr[i].w <= j){//不是作用卡,费用足够
							dp[j][k] = max(dp[j][k], dp[j - arr[i].w][k - 1] + arr[i].x);
						}
					}
				}
			}
			else {
				//进入该部分时,全部的魔法卡使用情况已经存入dp,之后的都不是魔法卡
				per(k, m_num, 0){//m_num是魔法卡总数量,可能有不用魔法卡才能的到最大攻击的情况
					per(j, W, 0){
						
						int tmp_w = 0;
						if (arr[i].is_s){
							is_s = true;
							tmp_w = max(0, arr[i].w - k);
						}
						//对于k张魔法卡,被作用卡卡费用减少k
						if (is_s && tmp_w <= j){
							dp[j][k] = max(dp[j][k], dp[j - tmp_w][k] + arr[i].x);
						}
						else if (!is_s && arr[i].w <= j){
							dp[j][k] = max(dp[j][k], dp[j - arr[i].w][k] + arr[i].x);
						}
					}
				}
			}

			is_s = false;
		}

		int ans = 0;

		rep(i, 0, m_num) ans = max(ans, dp[W][i]);//遍历费用是W的dp最好值,及为最大攻击力

		cout << ans << endl;
	}


	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值