题意:
有n个topic,每个topic的时间长度是ti。定义一个Lecture的时间长度为L。
问将这些topic放进Lecture中,最少需要几个Lecture,注意一个topic必须在一个Lecture内,不能断,且topic要按顺序。
然后又定义了一个学生不满意度的函数,用每个Lecture剩下的时间作为自变量,要求在Lecture数相同的情况下,不满意度最小。
解析:
最少Lecture很简单,扫一遍。
不满意度用记忆化搜索处理。
状态转移方程:
dp[ i ] [ j ] = min ( dp[ i ] [ j ] , dp [ i - 1 ] [ j - 1 ] + getscore(ti - sum) )
dp[i][j] 表示 i 个lecture上 j 个topic的最小不满意度。
对于当前lecture,当前topic选不选,选,则为dp [ i - 1 ] [ j - 1 ] + getscore(ti - sum);不选则为dp[i][j]。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
using namespace std;
const int maxn = 1000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = 4 * atan(1.0);
const double ee = exp(1.0);
int n, ti, c;
int topic[maxn];
int dp[maxn][maxn];
bool vis[maxn][maxn];//dp maybe negative
int getscore(int x)
{
if (x == 0)
return 0;
else if (x <= 10)
return -c;
else
return (x - 10) * (x - 10);
}
int dfs(int i, int j)
{
int& res = dp[i][j];
if (vis[i][j])
return res;
if (i == 0)
return j ? inf : 0;
vis[i][j] = true;
res = inf;
int sum = 0;
for (int k = j; k > 0; k--)
{
sum += topic[k];
if (ti < sum)
break;
res = min(res, dfs(i - 1, k - 1) + getscore(ti - sum));
}
return res;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int ncase = 0;
while (~scanf("%d", &n) && n)
{
scanf("%d%d", &ti, &c);
memset(dp, 0, sizeof(dp));
memset(vis, false, sizeof(vis));
int ans = 1;
int sum = 0;
for (int i = 1; i <= n; i++)
{
scanf("%d", &topic[i]);
sum += topic[i];
if (ti < sum)
{
sum = topic[i];
ans++;
}
}
if (ncase)
printf("\n");
printf("Case %d:\n", ++ncase);
printf("Minimum number of lectures: %d\n", ans);
printf("Total dissatisfaction index: %d\n", dfs(ans, n));
}
return 0;
}