肝任务(中二羊)

本文探讨了如何通过动态规划策略解决一款手机游戏中的肝任务问题,玩家需要在有限时间内获取足够活跃值并控制恶心度,以达成活动成就。核心算法涉及二维背包和状态转移方程,同时关注不恶心程度最大化或活跃值最大化问题。
摘要由CSDN通过智能技术生成

肝任务(task.cpp)

题面

【题目描述】

众所周知,敢玩手机游戏的人不是氯金大佬(能充钱)就是绝世肝帝(大量时间在线)。ZEY最近迷上了一款手机游戏,当然,ZEY非常穷,只能投入大量时间来肝任务,尽管ZEY浑身是肝,但是面对阴险的游戏策划,他终于肝!不!动!了!
现在这款游戏又在周末搞活动了,要达成活动成就需要不低于 \(n\) 点活跃值,在活动期间有 \(k\) 种任务可以完成,每种任务都能够不断重复完成。不过ZEY看到这个活动已经恶心到想吐了,如果他的恶心程度超过 \(m\) 点,他就会晕倒!(那当然就不能继续完成活动任务了)另外,ZEY发现明天就是星期一,但是自己—点作业都没写,所以他最多还能玩 \(t\) 个时间单位的游戏。
已知完成第 \(i\) 个任务,可以获得 \(x_{[i]}\) 点活跃值,但是ZEY也会增加 \(y_{[i]}\)点恶心度,同时会消耗 \(1\) 点单位时间。现在,ZEY想知道自己能不能达成活动成就,如果能达成,他还想知道自己最多能有多不恶心(用 \(m\) 减去累计的恶心度);如果不能达成,他也想知道最多可以获得多少活跃值。

【输入说明】

输入文件名为task.in。输入为多行
第一行输入4个整数,分别是 \(k,n,m,t\) ,数字间用空格隔开
接下来k行,每—行输入两个整数,分别是 \(x_{[i]}\)\(y_{[i]}\)

【输出说明】

输出文件名为task.out。输出—行,分两种情况:

  1. 如果能达成活动成就,输出大写字母 \(Y\) 以及最大的不恶心程度,用空格隔开
  2. 如果不能达成活动成就,输出大写字母 \(N\) 以及最多的活跃值,用空格隔开

输入样例1:

1 5 5 5 5
1 1

输出样例1:

Y 0

输入样例2:

2 12 8 3
3 1
4 3

输入样例2:

N 11

【样例说明】

对于样例1,完成 \(5\) 次人物刚好达成成就,不恶心程度为 \(0\)
对于样例2,容易证明无法达成,当完成1次人物1或2次任务2时,活跃值最大为 \(11\)

【数据范围】

\(1\le ,n,m,t\le 150\)\(1\le x_i,y_i\le 20\)

题解

题目考点:动态规划,动规,dp。背包。
背包特点:二维背包。
方程: \(dp_{j,p}=\max(dp_{j,p},dp_{j-1,p-kkk_{i,1}}+kkk_{i,0})\) 。其中 \(kkk_{i,0}\) 为活跃值(即 \(x_i\) ), \(kkk_{i,1}\) 为恶心度(即 \(y_i\) ), \(j\) 为时间, \(p\) 为恶心度。
翻译方程: 对于第 \(i\) 个活动:

  1. 做:\(dp_{j,p}=dp_{j-1,p-kkk_{i,1}}+kkk_{i,0}\)
  2. 不做:\(dp_{j,p}=dp{j,p}\)

选择方案是选最大值,所以 \(dp_{j,p}=\max(dp_{j,p},dp_{j-1,p-kkk_{i,1}}+kkk_{i,0})\)
所以代码:

for(int i=1;i<=k;++i)
	for(int j=1;j<=t;++j)
		for(int p=kkk[i][1];p<=m;++p)
			dp[j][p]=max(dp[j][p],dp[j-1][p-kkk[i][1]]+kkk[i][0]);

但是题目要求求最不恶心程度,所以设置一个bool类型的变量来设置,如下:

bool fff=false;
/*循环代码跳过,方程跳过。*/
if(dp[j][p]>=n)fff=true,ans=max(ans,m-p);

这里求的是最不恶心程度的最大值,也可以求最恶心程度的最小值。即

ans=0x7f7f7f7f7f;
/*省略一些代码*/ans=min(ans,p);

输出: \(m-ans\)
然后就贴代码:

#include<iostream>
#include<cstdio>
using namespace std;
class QIO{
	public:
		inline int read(){
			x=0,f=1,ch=getchar();
			while(ch<'0'||ch>'9'){
				if(ch=='-')f=-f;
				ch=getchar();
			}
			while(ch>='0'&&ch<='9'){
				x=(x<<3)+(x<<1)+(ch^48);
				ch=getchar();
			}
			return x*f;
		}
		inline void write(int a){
			if(a<0)a=-a,putchar('-');
			output((unsigned int)a);
			}
	private:
		void output(unsigned int a){
			if(a>9)output(a/10);
			putchar((a%10)^48);
		}
		int x;
		short f;
		char ch;
};
QIO qrw;//快速输入输出
int kkk[200][2],dp[1001][1001];
signed main(){
	freopen("task.in","r",stdin);
	freopen("task.out","w",stdout);
	int k,n,m,t,ans=0;
	k=qrw.read();
	n=qrw.read();
	m=qrw.read();
	t=qrw.read();
	bool fff=false;
	for(int i=1;i<=k;++i){
		kkk[i][0]=qrw.read();
		kkk[i][1]=qrw.read();
	}
	for(int i=1;i<=k;++i)
		for(int j=1;j<=t;++j)
			for(int p=kkk[i][1];p<=m;++p){
				dp[j][p]=max(dp[j][p],dp[j-1][p-kkk[i][1]]+kkk[i][0]);
				if(dp[j][p]>=n)fff=true,ans=max(ans,m-p);
			}
	if(fff){
		putchar('Y');
		putchar(' ');
		qrw.write(ans);
	}else{
		putchar('N');
		putchar(' ');
		qrw.write(dp[t][m]);
	} 
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值