题意:有n个主题。每堂课的时间是L。每个主题各要求t1,t2,...tn(1<=ti<=L)。对于每个主题,你要决定要哪堂课教。并且有如下的规则:
1.每个主题必须完整地包含在一堂课里。不能分成两部分教。
2.主题之间的顺序不能调换,即主题i必须在主题i+1之前教。
同时,如果在每堂课的最后如果能留有10分钟以内的时候,那么学生的不满意程序是最小的。不满意程度的计算如下所示:
D=0(如果剩下的时间是0)。
D=-c(如果剩下的时间在10分钟以内)。
D=(t-10)^2(剩下的情况)
1.每个主题必须完整地包含在一堂课里。不能分成两部分教。
2.主题之间的顺序不能调换,即主题i必须在主题i+1之前教。
同时,如果在每堂课的最后如果能留有10分钟以内的时候,那么学生的不满意程序是最小的。不满意程度的计算如下所示:
D=0(如果剩下的时间是0)。
D=-c(如果剩下的时间在10分钟以内)。
D=(t-10)^2(剩下的情况)
c是一个正值。
因为主题之间要按给出的顺序排列,这个限制很强,所以用贪心可以得出最少用多少节课,最后用DP去解决最小的不满意度就可以了。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define INF 1<<30
const int N=1005;
int t,c,a[N],map[N][N];
bool vis[N][N];
int fun(int),dp(int,int);
int main()
{
//freopen("607","r",stdin);
int n,t_cnt=0;
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
memset(vis,0,sizeof(vis));
memset(map,0,sizeof(map));
int cnt=0,temp=0;
scanf("%d%d",&t,&c);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
temp+=a[i];
if(temp>t) {cnt++,temp=a[i];}
}
if(t_cnt!=0) puts("");
printf("Case %d:\n",++t_cnt);
printf("Minimum number of lectures: %d\n",++cnt);
printf("Total dissatisfaction index: %d\n",dp(cnt,n));
}
return 0;
}
int dp(int x,int y)
{
bool &flag=vis[x][y];
int &res=map[x][y];
if(flag) return res;
else if(x==0)
{
flag=1;
res=(y==0?0:INF);
return res;
}
else
{
res=INF;
int temp=0;
for(int i=y;i>0;i--)
{
temp+=a[i];
if(temp>t) break;
int ans=dp(x-1,i-1);
if(ans!=INF) res=min(res,ans+fun(t-temp));
}
flag=1;
return res;
}
}
int fun(int temp)
{
if(temp==0) return 0;
else if(temp<=10) return -c;
else return (temp-10)*(temp-10);
}