动态规划题,设 dp[i][j] 表示前 i 节课,讲 j 个主题,最小的不满指数。
状态转移方程为 dp[i][j] = min(dp[i][j], dp[i - 1][k] + DI(sum[j] - sum[k])),表示前 i-1 节课讲前 k 个主题,第 i 节课讲第 k+1 个至第 j 个主题。
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 1005;
const int INF = 0x3f3f3f3f;
int dp[MAXN][MAXN]; //dp[i][j]表示前i节课,讲j个主题,最小的不满指数
int time[MAXN]; //每个主题所需的时间
int sum[MAXN]; //sum[i]表示前i个主题所需的时间
int L, C; //一节课的时间,常数C
//计算不满指数
int DI(int t)
{
t = L - t;
if (t == 0)
return 0;
else if (t >= 1 && t <= 10)
return -C;
else
return (t - 10) * (t - 10);
}
int main()
{
int Case = 1; //测试用例数
int n; //主题数
while (scanf("%d", &n) != EOF)
{
if (n == 0)
break;
scanf("%d %d", &L, &C);
sum[0] = 0;
for (int i = 1; i <= n; i++)
{
scanf("%d", &time[i]);
sum[i] = sum[i - 1] + time[i];
}
for (int i = 0; i <= n; i++)
{
dp[i][0] = 0;
for (int j = 1; j <= n; j++)
dp[i][j] = INF;
}
for (int i = 1; dp[i - 1][n] == INF; i++) //课程数,i-1节课无法讲n个主题
{
for (int j = i; j <= n && sum[j] <= i * L; j++) //主题数
{
for (int k = j - 1; k >= i - 1; k--) //第i节课讲第k+1个至第j个主题
{
if (sum[j] - sum[k] <= L && dp[i - 1][k] != INF)
dp[i][j] = min(dp[i][j], dp[i - 1][k] + DI(sum[j] - sum[k]));
else if (sum[j] - sum[k] > L)
break;
}
}
}
int index;
for (index = 1; index <= n; index++)
{
if (dp[index][n] != INF)
break;
}
if (Case > 1)
printf("\n");
printf("Case %d:\n\n", Case++);
printf("Minimum number of lectures: %d\n", index);
printf("Total dissatisfaction index: %d\n", dp[index][n]);
}
return 0;
}
继续加油。