背景 Background
在突破了重重难关后,工藤根据前三人留下的信息来到了一个充满实验室味道的房间……一道强光闪过..一个神秘而又熟悉的身影随着漫天飞舞的雪花徐徐下落。 "高中生侦探工藤新一,果然名不虚传……""这声音……你是!""在下Liqeuer,恭候多时了。" 隐约闪现的面孔……"你是maa04!""哼,没想到吧……想要救回小兰?过我这关吧!" "出招吧!"
(轰的一声,Liqeuer——maa04,即笨笨身后的一扇门迅速打开,展现在眼前的是两堆零件和一条岩浆“河”)
描述 Description
我们将第一堆零件定义为集合S1,第二堆定义为集合S2。
首先,S1的零件个数少于等于S2的零件个数。我们现在设N为S1的零件个数,从S2中挑选出N个零件,使得两个集合的匹配差最小。这样搭建出来的桥才能顺利通过岩浆“河”。
对于两个集合的匹配差在本题定义作此描述:
定义F(S1,S2)=min(|a1-b1|+|a2-b2|+|a3-b3|+...+|an-bn|){n为S1的元素个数,ai∈S1,bi∈S2},F(S1,S2)即为两个集合的匹配差。
输入格式 Input Format
第一行一个数testcase,表示测试数据组数(0<=testcase<=20)
每组数据的格式如下:
第一行两个数n1,n2(0<=n1<=n2<=500),n1表示第一堆零件的个数,n2表示第二堆零件的个数。
接下来n1行,每行一个数,表示S1的各个元素(不超过10000)。
再接下来n2行,每行一个数,表示S2的各个元素(同样不超过10000)。
输出格式 Output Format
输出testcase行,每行一个数。
第i行表示第i组数据的两个集合的匹配差值的最小值。
样例输入 Sample Input
3
10 10
1
2
3
4
5
6
7
8
9
20
10
11
12
13
14
15
16
17
18
19
4 5
1
2
3
4
5
6
7
8
9
8 12
3
4
6
8
10
16
21
25
29
34
25
12
42
35
62
19
31
49
46
37
样例输出 Sample Output
82
16
129
分析:
qsort+Dp;
f[i,j]表示S2选前j个匹配S1的前i个的最小值。
【参考程序】:
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
int a[510],b[510],F[510][510];
int n,m,t;
int cmp(const void *s,const void *t)
{
int i=*(int *)s,j=*(int *)t;
return i-j;
}
void solve()
{
memset(F,0,sizeof(F));
for (int i=0;i<=m;i++)
for (int j=0;j<=n;j++)
F[i][j]=1000000000;
for (int i=0;i<=n;i++) F[0][i]=0;
for (int i=1;i<=m;i++)
for (int j=1;j<=n;j++)
if (F[i][j-1]<F[i-1][j-1]+abs(a[i]-b[j]))
F[i][j]=F[i][j-1];
else F[i][j]=F[i-1][j-1]+abs(a[i]-b[j]);
}
int main()
{
scanf("%d",&t);
for (int o=1;o<=t;o++)
{
scanf("%d%d",&m,&n);
for (int i=1;i<=m;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) scanf("%d",&b[i]);
qsort(a+1,m,sizeof(int),cmp);
qsort(b+1,n,sizeof(int),cmp);
solve();
printf("%d\n",F[m][n]);
}
return 0;
}