1:接苹果:
【问题描述】
奶牛喜欢吃苹果。约翰有两棵苹果树,有 N 只苹果会从树上陆续落下。如果掉苹果的时候,贝西在那棵树下,她就能接住苹果。贝西一开始在第一棵树下。在苹果掉落之前,她有足够的时间来回走动,但她很懒,最多只愿意移动 K 次。请计算一下她最多可以接住几只苹果。
【输入】
• 第一行:两个整数 N 和 K,1 ≤ N ≤ 1000; 1 ≤ K ≤ 30
• 第 i + 1 行有一个整数 Ti,表示第 i 只苹果从哪棵树上掉落,1 表示从第一棵树,2 表示从第二棵树
【输出】
单个整数:表示能接住的最大苹果数量
【输入输出样例1】
bcatch.in | bcatch.out |
7 2 | 6 |
解释
先待在第一棵树下接住两个,然后移动到第二棵树下接住两个,再返回第一棵树接住最后两个
考试最开始的时候,我就一直想用一维DP来求解,最可怕的不是这个,而是我居然十分(脑残)地想出来了!30分的悲惨结局,后来才想到是三维的DP,用f[i][j][k]表示第i个苹果的时候,用了j次移动,k是用来表示位置的(不能用j的基偶性来表示,不然会炸)。程序:
#include<bits/stdc++.h>
using namespace std;
int n,k,a[1100],f[1100][31][3];
int main()
{
scanf("%d%d",&n,&k);
a[0]=1;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int j=0;j<=k;j++)
{
for(int i=1;i<=n;i++)
{
if(a[i]==1)
{
f[i][j][1]=max(f[i-1][j-1][2]+1,f[i-1][j][1]+1);
f[i][j][2]=f[i-1][j][2];
}
else
{
f[i][j][2]=max(f[i-1][j-1][1]+1,f[i-1][j][2]+1);
f[i][j][1]=f[i-1][j][1];
}
}
}
cout<<max(f[n][k][2],f[n][k][1]);
return 0;
}
但是在老师讲的时候,使用二维DP来写得:
没事懂很好理解。
T2;奶牛飞盘队:
【问题描述】
农夫顿因开始玩飞盘之后,约翰也打算让奶牛们享受飞盘的乐趣.他要组建一只奶牛飞盘队.
他的N(1≤N≤2000)只奶牛,每只部有一个飞盘水准指数Ri(1≤Ri≤100000).约翰要选出1只或多于1只奶牛来参加他的飞盘队.
约翰比较迷信,他的幸运数字是F,所以他要求队伍的总能力必须是F的倍数。请帮他算一下,符合这个要求的队伍组合有多少?由于这个数字很大,只要输出答案除以10^8 的余数就可以了。
【输入】
第一行:两个用空格分开的整数:N和F,1 ≤ N ≤ 2000,1 ≤ F ≤ 1000
第二行到N + 1行:第i + 1行有一个整数R i ,表示第i头奶牛的能力,1 ≤ R i ≤ 10^5
【输出】
【输入输出样例1】
fristeam.in | fristeam.out |
| 3 |
FJ has four cows whose ratings are 1, 2, 8, and 2. He will only accept a team whose rating sum is a multiple of 5.
FJ can pair the 8 and either of the 2's (8 + 2 = 10), or he can use both 2's and the 1 (2 + 2 + 1 = 5).
我在考试的时候,十分“机智”地想了一个用前缀和来一个一个减去的方法,这样就可以最短时间内求出来了,当然这只是我当时的想法,后来我发现会有后效性,就一直加位置,结果就拿到了10分的搞分。
正解:
第i只牛有两种可能性,要还是不要,所以,这个我们可以往0/1背包上考虑。因为我们要求的是F的整数倍的方案数,我们只考虑这种可能性无法满足最优子结构,按照我们常见的套路,我们显然要把 当前组成的累加和对Fmod的值进行存储。
程序:
#include<bits/stdc++.h>
using namespace std;
int n,a[2100],f,dp[2100][2100];
int mod=100000000;
int main()
{
scanf("%d%d",&n,&f);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
int t=a[i]%f;
if(!t) t=f;
dp[i][t]=1;
if(i==1) continue;
for(int j=1;j<=f;j++)
{
t=(j+a[i])%f;
if(!t)t=f;
dp[i][t]+=dp[i-1][j];
dp[i][j]+=dp[i-1][j];
dp[i][t]=dp[i][t]%mod;
dp[i][j]=dp[i][j]%mod;
}
}
cout<<dp[n][f];
return 0;
}
T3股票市场:
【问题描述】
【输入输出样例1】
stock.in | stock.out |
| 24 |
我一看到这题,就先想到了贪心,然后就想到了这样的程序,后来去写T4了,就没有管:
#include<bits/stdc++.h>
using namespace std;
int s,d,m,a[51][51],maxx,maxxi,t,num;
int main()
{
scanf("%d%d%d",&s,&d,&m);
for(int i=1;i<=s;i++)
{
for(int j=1;j<=d;j++) scanf("%d",&a[i][j]);
}
for(int j=1;j<d;j++)
{
maxx=-999999999;
for(int i=1;i<=s;i++)
{
t=a[i][j+1]-a[i][j];
if(t>maxx&&m>=a[i][j]) maxx=t,maxxi=i;
}
num=m/a[maxxi][j];
m=m%a[maxxi][j];
m+=num*a[maxxi][j+1];
}
cout<<m;
return 0;
}
当然这不是正解。
其实每天的利润就相当于今天买了,明天卖掉,然后再买。(这谁会这么买啊)。
因此第一天买的股票,第三天卖出去,可以当成第一天买的,第二天卖出去,然后在卖,第三天再卖出去,这样就可以把每一天的利润给分开了。这样我们得到一个贪心算法,依次考虑每相邻两天,前一天买入后一天全部卖出所能得到的最大收益,而这正是个简单的背包问题:股票就是物品,花费就是前一天的价格,收益就是后一天的价格,背包就是资金。
因此对于每一天,就是一个完全背包,重量为当天的价格,价值为该股票到第二天的利润;可以用f[i][j]表示前i个股票用j块钱的最大利润。DP方程:f[i][j]=f[i-1][j-a[i]]+a[i+1]-a[i];
。。先鸽l