题目链接:点击这里
题目大意:
q
q
q 组数据,每组数据给出
n
n
n 个物品,第
i
i
i 个物品在
t
i
t_i
ti 时取出花费为
0
0
0 ,在其余时间取出花费是
a
b
s
(
t
i
−
t
i
′
)
abs(t_i-t^{'}_i)
abs(ti−ti′) ,求
∑
i
=
1
n
(
a
b
s
(
t
i
−
t
i
′
)
)
\sum_{i=1}^n(abs(ti-t^{'}_i))
∑i=1n(abs(ti−ti′)) 的最小值
题目分析:
设状态
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 为前
i
i
i 个时刻取出了前
j
j
j 物品的花费,显然有转移方程:
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
−
1
]
[
j
−
1
]
+
a
b
s
(
t
[
j
]
−
i
)
)
dp[i][j]=min(dp[i−1][j],dp[i−1][j−1]+abs(t[j]-i))
dp[i][j]=min(dp[i−1][j],dp[i−1][j−1]+abs(t[j]−i)) ,这个方程可以把第一维压掉通过倒序转移(类似与背包),时间最坏情况是从
n
n
n 时刻开始拿出物品,最多到
2
n
2n
2n 时刻全部拿完
其实这个题是很像是背包的,背包的容量为
n
n
n ,每个物品体积是
1
1
1 ,花费是
a
b
s
(
t
i
−
t
i
′
)
abs(t_i-t^{'}_i)
abs(ti−ti′) ,就可以设
d
p
[
i
]
dp[i]
dp[i] 表示容量为
i
i
i 的时候的最小价值,用背包方程求解
d
p
[
n
]
dp[n]
dp[n] 即可
具体细节见代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int read()
{
int res = 0,flag = 1;
char ch = getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = getchar();
}
while(ch>='0' && ch<='9')
{
res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
ch = getchar();
}
return res*flag;
}
const int maxn = 205;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
int t[maxn],dp[maxn];
int main()
{
int q = read();
while(q--)
{
int n = read();
for(int i = 1;i <= n;i++)
t[i] = read();
sort(t+1,t+n+1);
memset(dp,0x3f,sizeof(dp));
dp[0] = 0;
for(int i = 1;i <= 2*n;i++) //枚举时间
for(int j = n;j;j--) //枚举物品
dp[j] = min(dp[j],dp[j-1]+abs(t[j]-i));
printf("%d\n",dp[n]);
}
return 0;
}