C. Chef Monocarp || dp
首先得到结论:先做好的菜应该先出(至少不慢:eg. 做好5 6 出菜1 2)
那么先把菜按做好的时间排序。
定义dp[i][j]为:前i分钟做了j道菜,时间差的最小值。那这个状态是由什么转移过来的呢?考虑第i分钟是否做了第j道菜。如果做了,那么就说明前i-1分钟做了j-1道菜,那么就是由dp[i-1][j-1]转移过来的,差值为(a[i] - j)的绝对值;如果没做,那么就说明前i-1分钟做了j道菜,那么就是由dp[i-1][j]转移过来的。然后取两种情况的最小值即可。
注意,对于每一个i,遍历j的时候都不应该超过i,因为同一时间最多只能出一道菜,所以前i分钟最多做i道菜。
初始化问题:
对于不可能的情况:eg. j > i,处理方法:if判断或者初始化为INF。
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 1e5 + 4; int a[222], dp[306][222]; int main() { int q; cin >> q; while(q--) { int n; cin >> n; for(int i = 1; i <= n; ++i) scanf("%d", &a[i]); sort(a + 1, a + 1 + n); //for(int j = 1; j <= 300; ++j) dp[0][j] = 333; for(int i = 1; i <= 300; ++i) { for(int j = 1; j <= i && j <= n; ++j) { if(j == i) dp[i][j] = dp[i-1][j-1] + abs(a[j] - i); else dp[i][j] = min(dp[i-1][j-1] + abs(a[j] - i), dp[i-1][j]); } } cout << dp[300][n] << endl; } return 0; }
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 1e5 + 4; const int INF = 0x3f3f3f3f; int a[222], dp[306][222]; int main() { int q; cin >> q; while(q--) { int n; cin >> n; for(int i = 1; i <= n; ++i) scanf("%d", &a[i]); sort(a + 1, a + 1 + n); for(int i = 0; i <= 300; ++i) for(int j = 0; j <= 200; ++j) dp[i][j] = INF; dp[0][0] = 0; for(int i = 1; i <= 300; ++i) { dp[i][0] = 0; for(int j = 1; j <= i && j <= n; ++j) { //if(j == i) dp[i][j] = dp[i-1][j-1] + abs(a[j] - i); dp[i][j] = min(dp[i-1][j-1] + abs(a[j] - i), dp[i-1][j]); } } cout << dp[300][n] << endl; } return 0; }