中二羊专题:肝任务

原题

肝任务(task.cpp)

【题目描述】

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

【输入说明】

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

【输出说明】

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

  1. 如果能达成活动成就,输出大写字母 Y Y Y 以及最大的不恶心程度,用空格隔开
  2. 如果不能达成活动成就,输出大写字母 N N 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 5 5 次人物刚好达成成就,不恶心程度为 0 0 0
对于样例2,容易证明无法达成,当完成1次人物1或2次任务2时,活跃值最大为 11 11 11

【数据范围】

1 ≤ , n , m , t ≤ 150 1\le ,n,m,t\le 150 1,n,m,t150 1 ≤ x i , y i ≤ 20 1\le x_i,y_i\le 20 1xi,yi20

题解:

题目考点:动态规划,动规,dp。背包。
背包特点:二维背包。
方程: d p j , p = m a x ( d p j , p , d p j − 1 , p − k k k i , 1 + k k k i , 0 ) dp_{j,p}=max(dp_{j,p},dp_{j-1,p-kkk_{i,1}}+kkk_{i,0}) dpj,p=max(dpj,p,dpj1,pkkki,1+kkki,0) 。其中 k k k i , 0 kkk_{i,0} kkki,0 为活跃值(即 x i x_i xi ), k k k i , 1 kkk_{i,1} kkki,1 为恶心度(即 y i y_i yi ), j j j 为时间, p p p 为恶心度。
翻译方程: 对于第 i i i 个活动:

  1. 做:
    d p j , p = d p j − 1 , p − k k k i , 1 + k k k i , 0 dp_{j,p}=dp_{j-1,p-kkk_{i,1}}+kkk_{i,0} dpj,p=dpj1,pkkki,1+kkki,0
  2. 不做:
    d p j , p = d p j , p dp_{j,p}=dp{j,p} dpj,p=dpj,p

选择方案是选最大值,所以 d p j , p = m a x ( d p j , p , d p j − 1 , p − k k k i , 1 + k k k i , 0 ) dp_{j,p}=max(dp_{j,p},dp_{j-1,p-kkk_{i,1}}+kkk_{i,0}) dpj,p=max(dpj,p,dpj1,pkkki,1+kkki,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 − a n s m-ans mans
然后就贴代码:

#include
#include
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;
}

你可能感兴趣的:(中二羊专题,c++,动态规划)