题目大意:有n(n大于等于1小于等于1000)个主题,每个主题要花费t1,t2,……,tn(每个ti都不会大于L)的时间来讲,每个讲座L(L大于等于1小于等于500)分钟;安排讲座有两个规则:
不能讲一个主题分在两个讲座讲;
必须按顺序讲,即ti要在ti-1之后讲。
每个讲座都有一个DI值,(即不满意值)设t为提前下课的分钟数,则:
DI=0(若t=0)或DI=-C(若t大于等于1小于等于10)或DI=(t-10)的平方(若t大于10)。
求出最少安排多少个讲座能将所有主题讲完,并且求出在最少讲座的情况下不满意度的最小值是多少。
先用贪心,尽量把课往前安排,求出最少用多少次讲座可以讲完。记b[i]为前i个讲座最多包含的主题的数量(即前i个讲座最多包含b[i]个主题,再多就安排不下);再从后往前贪心,记c[i]为前i个讲座最少包含的主题的数量(即前i个讲座最少安排c[i]个主题,否则就不能产生最优解了)。之后动态规划。d[i][j]表示前i个讲座包含j个主题最小的不满意值,用e[i][j]表示主题i到j安排在一个讲座内,DI值是多少。
状态转移方程:d[i][j]=min { d[i-1][u]+e[u+1][j] }(j从c[i]变化到b[i],u从c[i-1]变化到b[i-1])
#include<stdio.h>
#include<stdlib.h>
int a[1100];
int b[1100];
int c[1100];
int d[1100][1100];
int sum[1100][1100];
int main(void)
{
int i,j,n,m,p,q,u,v,min,co;
co=0;
scanf("%d",&n);
while(n!=0)
{
co++;
scanf("%d%d",&m,&p);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(i=1;i<n;i++)
{
sum[i][i]=a[i];
for(j=i+1;j<=n;j++)
{
sum[i][j]=sum[i][j-1]+a[j];
}
}
sum[n][n]=a[n];
u=0;
v=1;
for(i=1;i<=n;i++)
{
if(u+a[i]>m)
{
b[v]=i-1;
i--;
u=0;
v++;
}
else
{
u=u+a[i];
}
}
b[v]=n;
c[v]=n;
b[0]=v;
u=0;
v--;
for(i=n;i>=1;i--)
{
if(u+a[i]>m)
{
c[v]=i;
i++;
u=0;
v--;
}
else
{
u=u+a[i];
}
}
for(u=c[1];u<=b[1];u++)
{
if(sum[1][u]==m)
{
d[1][u]=0;
}
else if(m-sum[1][u]>10)
{
d[1][u]=(m-sum[1][u]-10)*(m-sum[1][u]-10);
}
else
{
d[1][u]=-p;
}
}
for(i=2;i<=b[0];i++)
{
for(u=c[i];u<=b[i];u++)
{
min=100000000;
for(v=c[i-1];v<=b[i-1];v++)
{
if((v<=u)&&(sum[v+1][u]<=m))
{
if(sum[v+1][u]==m)
{
q=d[i-1][v];
}
else if(m-sum[v+1][u]>10)
{
q=d[i-1][v]+(m-sum[v+1][u]-10)*(m-sum[v+1][u]-10);
}
else
{
q=d[i-1][v]-p;
}
if(q<min)
{
min=q;
}
}
}
d[i][u]=min;
}
}
printf("Case %d:\n",co);
printf("Minimum number of lectures: %d\n",b[0]);
printf("Total dissatisfaction index: %d\n",d[b[0]][n]);
scanf("%d",&n);
if(n!=0)
{
printf("\n");
}
}
return 0;
}