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