XMUT acdream DP专场

102 篇文章 0 订阅
99 篇文章 0 订阅


A - 小彭玉的扫荡食堂计划


Problem Description

哗啦啦村的食堂很奇怪,就是如果这个饭卡所剩金额低于5元的话,这个饭卡就不能刷了。

也就是说,只要这个饭卡金额大于等于5元,就可以随便刷~

 

有一天,小彭玉看了看哗啦啦食堂的饭,“哇,好好吃!我要全部都买下来!”

但是小彭玉并没有那么多钱,于是他准备充分利用自己的钱,去买这些食物!

请问最后小彭玉的饭卡余额最少能到多少?

Input

多组测试数据(最多100组)

第一行 n,表示有n个菜

第二行 接下来n个数字,a[i]表示第i道菜多少钱

第三行 一个数m,表示小彭玉的饭卡,一开始有m元

1<=n<=1000,1<=a[i]<=10000,1<=m<=10000

Output
输出一个整数,表示最后饭卡显示的金额数
Sample Input
1
10000
6
10
1 2 3 2 1 1 2 3 2 1
50
Sample Output
-9994
32

分析:01背包思想。

AC  code:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#define LL long long
#define MAXN 1000010
using namespace std;
int a[MAXN];
int F[MAXN];
int n,m,mm,mmi;
LL ans;
int main()
{
	int i,j;
	while(scanf("%d",&n)!=EOF)
	{
		mm=0;
		mmi=0;
		for(i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			if(a[i]>mm)
			{
				mm=a[i];
				mmi=i;
			}
		}
		scanf("%d",&m);
		if(m<5)
		{
			ans=m;
		}
		else
		{
			memset(F,0,sizeof(F));
			int V=m-5;
			for(i=1;i<=n;i++)
			{
				if(mmi==i)
					continue;
				for(j=V;j>=a[i];j--)
				{
					F[j]=max(F[j],F[j-a[i]]+a[i]);
				}
			}
			ans=m-F[V]-mm;
		}
		printf("%lld\n",ans);
	}
	return 0;
 } 



B - 喵哈哈村的挑衅



Problem Description

喵哈哈村就挨着哗啦啦村,他们很喜欢和哗啦啦村互黑~

今天也不例外,喵哈哈派了智商流选手 青君 去挑衅哗啦啦村

哗啦啦村当然不会畏惧这种弱的挑衅,于是派出了谈笑风生的 狗哥 应战!

青君和狗哥站在一个空地上,空地上有两排物品,每排都有n个,每个物品都有一定价值

每次每个人只能拿第一排的最左边的物品,或者拿第一排最右边的物品,或者第二排最左边的物品,或者第二排最右边的物品

狗哥 和 青君轮流拿~

青君先手,请问在狗哥绝顶聪明的情况下,青君所拿物品的最大价值是多少?

Input

多组测试数据,最多100组

第一行 一个数字n,表示每排有多少个物品。

第二行 n个数字,a[i]表示第一排,第i个物品的价值是多少

第三行 n个数字,b[i]表示第二排,第i个物品的价值是多少

1<=n<=25 1<=a[i]<=1000 1<=b[i]<=1000

Output
对于每组测试数据,输出一个整数,表示青君所能获得的最大价值是多少
Sample Input
1
23
53
3
10 100 20
2 4 3 
Sample Output
53
105 

分析:区间DP,具体见代码注释。

AC  code:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#define LL long long
#define MAXN 1000010
using namespace std;
int n,L1,R1,L2,R2;
int a[33],b[33];
bool vis[33][33][33][33];//标记该状态是否记录过,即是否已经存在该状态下的dp值,存在就直接将值返回给程序去调用即可 
int dp[33][33][33][33];//dp[l1][r1][l2][r2]表示在当前状态下所获得的最大价值,即在第一排区间为l1~r1,
int sum1[33],sum2[33];//第二排区间l2~r2的状态下 
int qujian_dp(int l1,int r1,int l2,int r2)
{
	if(vis[l1][r1][l2][r2])//状态记忆化,避免重复深搜 
		return dp[l1][r1][l2][r2];
	vis[l1][r1][l2][r2]=true;
	int sum=0;
	int ans=0;
	if(l1<=r1)
		sum+=(sum1[r1]-sum1[l1-1]);
	if(l2<=r2)
		sum+=(sum2[r2]-sum2[l2-1]);
	if(l1<=r1)
	{
		ans=max(ans,sum-qujian_dp(l1+1,r1,l2,r2));//两人轮流取最大值 ,因为dp四维数组一开始初始化为0,
		ans=max(ans,sum-qujian_dp(l1,r1-1,l2,r2));//所以递归到最底层后将返回0,于是回溯得到sum-0,而sum即是 
	}											  //前递归所取的左右端点值a[i]或b[i],然后一直回溯
	if(l2<=r2)
	{
		ans=max(ans,sum-qujian_dp(l1,r1,l2+1,r2));
		ans=max(ans,sum-qujian_dp(l1,r1,l2,r2-1));
	}
	dp[l1][r1][l2][r2]=ans;//回溯时将之前递归所取的左右端点值a[i]或b[i]赋给ans,然后赋值给对应的dp状态 
	return dp[l1][r1][l2][r2];//一直回溯返回,最后返回第一个人所能获得的最大价值 
}
int main()
{
	int i;
	while(scanf("%d",&n)!=EOF)
	{
		memset(sum1,0,sizeof(sum1));
		memset(sum2,0,sizeof(sum2));
		memset(vis,false,sizeof(vis));
		memset(dp,0,sizeof(dp));
		for(i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			sum1[i]=sum1[i-1]+a[i]; 
		}
		for(i=1;i<=n;i++)
		{
			scanf("%d",&b[i]);
			sum2[i]=sum2[i-1]+b[i];
		}
		printf("%d\n",qujian_dp(1,n,1,n));
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林下的码路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值