Educational Codeforces Round 97 (Rated for Div. 2) C. Chef Monocarp(dp动态规划)

题目链接:https://codeforc.es/contest/1437/problem/C

Chef Monocarp has just put n dishes into an oven. He knows that the i-th dish has its optimal cooking time equal to ti minutes.

At any positive integer minute T Monocarp can put no more than one dish out of the oven. If the i-th dish is put out at some minute T, then its unpleasant value is |T−ti| — the absolute difference between T and ti. Once the dish is out of the oven, it can’t go back in.

Monocarp should put all the dishes out of the oven. What is the minimum total unpleasant value Monocarp can obtain?

Input
The first line contains a single integer q (1≤q≤200) — the number of testcases.

Then q testcases follow.

The first line of the testcase contains a single integer n (1≤n≤200) — the number of dishes in the oven.

The second line of the testcase contains n integers t1,t2,…,tn (1≤ti≤n) — the optimal cooking time for each dish.

The sum of n over all q testcases doesn’t exceed 200.

Output
Print a single integer for each testcase — the minimum total unpleasant value Monocarp can obtain when he puts out all the dishes out of the oven. Remember that Monocarp can only put the dishes out at positive integer minutes and no more than one dish at any minute.

Example

input

6
6
4 2 4 4 5 2
7
7 7 7 7 7 7 7
1
1
5
5 1 2 4 3
4
1 4 4 4
21
21 8 1 4 1 5 21 1 8 21 11 21 11 3 12 8 19 15 9 11 13

output

4
12
0
0
2
21

Note
In the first example Monocarp can put out the dishes at minutes 3,1,5,4,6,2. That way the total unpleasant value will be |4−3|+|2−1|+|4−5|+|4−4|+|6−5|+|2−2|=4.

In the second example Monocarp can put out the dishes at minutes 4,5,6,7,8,9,10.

In the third example Monocarp can put out the dish at minute 1.

In the fourth example Monocarp can put out the dishes at minutes 5,1,2,4,3.

In the fifth example Monocarp can put out the dishes at minutes 1,3,4,5.

题意

有 n 个菜,每个菜的最优出锅的时间 t[i],如果一个菜从时刻 T 出锅,那么会花费 |T - t[i]|,问把 n 个菜全都拿出来的最小花费。

分析

这题在打比赛的时候不晓得为什么没有想出 dp 方法。。。
想通以后还是挺巧妙的。

我们定义 dp[i][j] 表示到第 i 时刻拿出了 j 道菜的最小花费。
对于每一个时刻:1、拿一盘菜;2、不拿
所以状态转移方程就是 dp[i][j] = Min(dp[i][j], dp[i - 1][j], dp[i - 1][j - 1] + abs(a[j] - i));
边界很明显,dp[x][0] 肯定是0,因为拿 0 盘菜。

在 2n 时间内必定可以拿完。

代码
#include<bits/stdc++.h>
using namespace std;

int t;
int n;
int a[207];
int dp[407][207];

int Min(int x, int y, int z)
{
	if(x <= y && x <= z) return x;
	if(y <= x && y <= z) return y;
	if(z <= x && z <= y) return z;
}

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		memset(dp, 0x3f3f3f3f, sizeof(dp));
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		sort(a + 1, a + 1 + n);
		dp[0][0] = 0;
		for(int i=1;i<=n*2;i++)
		{
			dp[i][0] = 0;
			for(int j=1;j<=n;j++)
				dp[i][j] = Min(dp[i][j], dp[i - 1][j], dp[i - 1][j - 1] + abs(a[j] - i));
		}
		printf("%d\n",dp[n * 2][n]);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值