题目大意:Alfred要准备一些菜,每天一道菜,每个菜有收益和花费,如果连续两天准备同一道菜,收益减半,连续三天或更多,则不获得好感值,求在预算内的最多收益并输出每一天准备的菜。如果多个情况能获得相同的收益,输出花费较少的,如果还有多个,随意输出。
用d[i][j][u][0]表示前i天,花费至少j,第i天为第u道菜且第i-1天不为第u道菜时,最大的收益,
用d[i][j][u][1]表示前i天,花费至少j,第i天为第u道菜且第i-1天为第u道菜时,最大的收益。
a[u].cost和a[u].ben表示第u道菜的花费和收益。
对于d[i][j][u][0],由于它的前一天的菜不是u,所以找到前一天花费不超过j-a[u].cost,且最后一道菜(也就是第i-1天的菜)不是u时的最大收益是多少,就可以完成递推。
实际上只需要存储最大的3个收益值的信息(原因是3个中必然有一个的第i-1天的菜不和u相同)。在程序中用max[j][0],max[j][1],max[j][2]分别表示第一大,第二大,第三大收益值时的信息(当然也可以遍历一遍i-1天的情况,但这样复杂度升高)。max的第一维不用保存,每次运算完前两维时更新max数组。
对于d[i][j][u][1],它的前一天的菜是u,就由d[i-1][j-a[u].cost][u][0]或d[i-1][j-a[u].cost][u][1]递推而来。
程序将收益值乘2,在运算过程中避免浮点运算。
总体复杂度为O(n*m*k)
#include<stdio.h>
#include<stdlib.h>
typedef struct
{
int cost;
int ben;
}Coo;
typedef struct
{
int num;
int rep;
int ben;
}Maxt;
Coo a[110];
int b[110];
Maxt max[110][3];
int d[25][110][55][2];
int pre[25][110][55][2][2];
int main(void)
{
int i,j,u,v,p,q,n,m,uu,vv,pp,qq,ans,min;
scanf("%d%d%d",&n,&m,&p);
while((n!=0)||(m!=0)||(p!=0))
{
min=(1<<30);
for(i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
a[i].cost=u;
a[i].ben=v*2;
min=(u<min)?u:min;
}
if(min*n>p)
{
printf("0.0\n");
}
else if(m==1)
{
ans=a[1].ben+a[1].ben/2;
printf("%d.%d\n",ans/2,ans%2==0?0:5);
printf("1");
for(i=2;i<=n;i++)
{
printf(" 1");
}
printf("\n");
}
else
{
for(j=1;j<=p;j++)
{
max[j][0].ben=max[j][1].ben=max[j][2].ben=-(1<<30);
for(u=1;u<=m;u++)
{
v=j-a[u].cost;
d[1][j][u][1]=-(1<<30);
if(v<0)
{
d[1][j][u][0]=-(1<<30);
}
else
{
d[1][j][u][0]=a[u].ben;
}
if(d[1][j][u][0]>max[j][0].ben)
{
max[j][2]=max[j][1];
max[j][1]=max[j][0];
max[j][0].ben=d[1][j][u][0];
max[j][0].rep=0;
max[j][0].num=u;
}
else if(d[1][j][u][0]>max[j][1].ben)
{
max[j][2]=max[j][1];
max[j][1].ben=d[1][j][u][0];
max[j][1].rep=0;
max[j][1].num=u;
}
else if(d[1][j][u][0]>max[j][2].ben)
{
max[j][2].ben=d[1][j][u][0];
max[j][2].rep=0;
max[j][2].num=u;
}
}
}
for(i=2;i<=n;i++)
{
for(j=1;j<=p;j++)
{
for(u=1;u<=m;u++)
{
v=j-a[u].cost;
if(v<=0)
{
d[i][j][u][0]=d[i][j][u][1]=-(1<<30);
}
else
{
if(max[v][0].num!=u)
{
d[i][j][u][0]=max[v][0].ben+a[u].ben;
pre[i][j][u][0][0]=max[v][0].num;
pre[i][j][u][0][1]=max[v][0].rep;
}
else if(max[v][1].num!=u)
{
d[i][j][u][0]=max[v][1].ben+a[u].ben;
pre[i][j][u][0][0]=max[v][1].num;
pre[i][j][u][0][1]=max[v][1].rep;
}
else
{
d[i][j][u][0]=max[v][2].ben+a[u].ben;
pre[i][j][u][0][0]=max[v][2].num;
pre[i][j][u][0][1]=max[v][2].rep;
}
if(d[i-1][v][u][0]+a[u].ben/2>d[i-1][v][u][1])
{
d[i][j][u][1]=d[i-1][v][u][0]+a[u].ben/2;
pre[i][j][u][1][0]=u;
pre[i][j][u][1][1]=0;
}
else
{
d[i][j][u][1]=d[i-1][v][u][1];
pre[i][j][u][1][0]=u;
pre[i][j][u][1][1]=1;
}
}
}
}
for(j=1;j<=p;j++)
{
max[j][0].ben=max[j][1].ben=max[j][2].ben=-(1<<30);
for(u=1;u<=m;u++)
{
if(d[i][j][u][0]>max[j][0].ben)
{
max[j][2]=max[j][1];
max[j][1]=max[j][0];
max[j][0].ben=d[i][j][u][0];
max[j][0].rep=0;
max[j][0].num=u;
}
else if(d[i][j][u][0]>max[j][1].ben)
{
max[j][2]=max[j][1];
max[j][1].ben=d[i][j][u][0];
max[j][1].rep=0;
max[j][1].num=u;
}
else if(d[i][j][u][0]>max[j][2].ben)
{
max[j][2].ben=d[i][j][u][0];
max[j][2].rep=0;
max[j][2].num=u;
}
if(d[i][j][u][1]>max[j][0].ben)
{
max[j][2]=max[j][1];
max[j][1]=max[j][0];
max[j][0].ben=d[i][j][u][1];
max[j][0].rep=1;
max[j][0].num=u;
}
else if(d[i][j][u][1]>max[j][1].ben)
{
max[j][2]=max[j][1];
max[j][1].ben=d[i][j][u][1];
max[j][1].rep=1;
max[j][1].num=u;
}
else if(d[i][j][u][1]>max[j][2].ben)
{
max[j][2].ben=d[i][j][u][1];
max[j][2].rep=1;
max[j][2].num=u;
}
}
}
}
ans=-(1<<30);
for(j=1;j<=p;j++)
{
for(u=1;u<=m;u++)
{
if(d[n][j][u][0]>ans)
{
uu=u;
vv=0;
q=j;
ans=d[n][j][u][0];
}
if(d[n][j][u][1]>ans)
{
uu=u;
vv=1;
q=j;
ans=d[n][j][u][1];
}
}
}
for(i=n;i>=1;i--)
{
b[i]=uu;
pp=pre[i][q][uu][vv][0];
qq=pre[i][q][uu][vv][1];
u=q-a[uu].cost;
uu=pp;
vv=qq;
q=u;
}
printf("%d.%d\n",ans/2,ans%2==0?0:5);
printf("%d",b[1]);
for(i=2;i<=n;i++)
{
printf(" %d",b[i]);
}
printf("\n");
}
scanf("%d%d%d",&n,&m,&p);
}
return 0;
}