//动态规划 //这题的关键在于先排序,只有先排序,后面动规的思路才能出来,我就是想不到得先排序,卡了好久还得别人提醒 //我是NC不解释 //题意是对2个集合寻找N对数对,使得数对的距离之和最小 //如果你先排好序,那么用DP(i,j)表示A集合的前i个点与B集合前j个点的最优值 //那么对于第i+1个A集合的点而言,他的最优解就是前i个点与B集合前j个点的最优值加上第i+1个点与第j+1个点的距离 //或许i+1与j+1配对不是最好的,它可能比上一个状态DP(i+1,j)要差 //综上 //动态转移方程就是 //dp(i,j) = min(dp(i-1,j-1) + dis(i,j),dp(i,j-1)); //当然这题的边界处理也比较重要 //最初的状态自然是对排序后的点按集合下表按顺序配对 //1-1,2-2,3-3......n-n,X-n+1...X-m;详细的处理可见代码 #include<iostream> #include<algorithm> #include<cstring> #include<cstdio> using namespace std; int A[505],B[505],N,M; int dp[505][505],dis[505][505]; int main() { //freopen("in.txt","r",stdin); int T; scanf("%d",&T); while(T--) { scanf("%d%d",&N,&M); memset(dp,0,sizeof(dp)); for(int i = 1;i <= N;++i) scanf("%d",&A[i]); for(int j = 1;j <= M;++j) scanf("%d",&B[j]); sort(A+1,A+N+1); sort(B+1,B+M+1); for(int i = 1;i <= N;++i) for(int j = 1;j <= M;++j) dis[i][j] = abs(A[i] - B[j]); for(int i = 1;i <= N;++i) { if(i == 1) dp[i][i] = dis[1][1]; else dp[i][i] = dp[i-1][i-1] + dis[i][i];//初始化边界 } for(int i = 1;i <= N;++i) for(int j = i+1;j <= M;++j) dp[i][j] = min(dp[i-1][j-1] + dis[i][j],dp[i][j-1]);//状态转移 printf("%d/n",dp[N][M]); } return 0; }