有个牛,好多题了,都是牛。然后她想吃苹果。有两个树,单位时间,在一棵树上会掉下来一个苹果。她必须在这个时间正好站到了这棵树下,才能吃到这个苹果。现在给你一共有T(1000)个单位时间,以及每个单位时间是哪一颗树上要掉苹果,这个牛可以瞬间从一棵树到达另一棵树下面,但是这种瞬移技能只能释放最多w(30)次 。问你这个牛最多可以吃到多少苹果。(注:牛一开始在1号树下)ps:要是问西瓜就好了,因为西瓜不长在树上····
思路:
设a[i][j][k]表示这个牛在第i个苹果掉下来时,在j号树下,用了k次技能,所能得到的最多的苹果数。
递推公式:a[i][j][k]=max(a[i-1][j][k],a[i-1][!j][k-1]); if(v[i]==j)a[i][j][k]++;
边界条件:a[1][j][k];a[i][j][0];
关于递推公式以及边界条件的解释:
这个牛在第i个苹果掉下来的时候,在第j号树下,用了k次技能。能得到这个状态的上一状态为:这个牛在第i-1个苹果掉下来的时候,在第!j号树下,用了k-1次技能;或者这个牛在第i-1个苹果掉下来的时候,在第j号树下,用了k次技能。(关键也就是这个牛在第i-1个苹果掉下来和第i个苹果掉下来之间,有没有使用技能)然后如果,这个苹果他接到了,就+1呗~
然后是关于边界条件,很适合想想一个三维的表格来储存数组a(虽然想画个三维图,但是用笔画的图烂的掉渣,估计大家也看不清,就自己想象吧),这样的话,如果要推出第i层的一个,就需要知道第i-1层的两个格(沿i轴-1的一个,以及同i-1平面内无相交边的另一个)。这样,在i取1的时候,就找不到对应的i-1平面了,所以要确定边界a[1][j][k];同样,在k=0时就找不到对应的k-1了,所以也要确定边界a[i][j][0]。另外十分要注意,开始的时候在1号树下面,所以一切在2号数下面翻转0次得到的苹果数都是-inf。
然后三层循环为什么从外到内的顺序为ikj:
还是有些疑问,不过目前对于这道题来看,调换ik的内外层关系并没有发生错误。对于三维图来说,只不过是改变了各个格的数值确定的顺序。然后就是对递推公式理解上就不太好解释了(其实也是可以解释的):一个一个的用技能,在第i个格用技能得到的总金额可以根据在第i-1个格用技能(a[i-1][j][k])或者不用这个技能(a[i-1][!j][k-1]) 两种情况来确定。
#include
#include
#define N 1050
#define W 40
#define inf 0x3f3f3f3f
using namespace std;
int n;
int w;
bool t[N]={0};
int a[N][2][W]={0};
void input()
{
cin>>n>>w;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
if(x==2)t[i]=1;
}
}
void init()
{
int s=0;
a[0][1][0]=-inf;
for(int i=1;i<=n;i++)//确定a[i][j][0]
{
if(t[i]==0)
{
s++;
a[i][0][0]=s;
}
a[i][1][0]=-inf; //开始的时候在1号树下面,所以一切在2号数下面翻转0次得到的苹果数都是-inf
}
for(int k=1;k<=w;k++)//确定a[1][j][k]
{
for(int j=0;j<=1;j++)
{
if(t[1]==j)
{
a[1][j][k]=1;
}
}
}
}
void dp()
{
init();//确定边界条件
for(int i=2;i<=n;i++)
{
for(int k=1;k<=w;k++)
{
for(int j=0;j<=1;j++)
{
a[i][j][k]=max(a[i-1][j][k],a[i-1][!j][k-1]);
if(t[i]==j)
{
a[i][j][k]++;
}
}
}
}
}
int find()
{
int max=-inf;
for(int i=0;i<=1;i++)
{
for(int j=0;j<=w;j++)
{
if(max