首页 > 代码库 > UVA 1534 - Taekwondo(dp)

UVA 1534 - Taekwondo(dp)

题目链接:1534 - Taekwondo

题意:两组人比赛,一组n1人,一组n2人,选择min(n1,n2)组出来,要求两两人重量差绝对值之和最小。
思路:首先先预处理让n1变成人少的一组,人少的每个人都必须去匹配,dp[i][j] i表示n1组第i个人,j表示第二组多少人没匹配,于是匹配的时候n1组的第i人就和n2组的第i + j的人去匹配,然后进行状态转移
dp[i][j] = {dp[i - 1][k] + fabs(a1[i] - a2[i + j]), (0 <= k <= abs(n1 - n2)},这样时间复杂度要O(n^3),进行优化,dp[i - 1][k]可以在第二城循环的时候顺便维护一个最小值Min,这样复杂度优化到O(n^2)。
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stdlib.h>
#include <math.h>
using namespace std;
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define INF 0x3f3f3f3f
const int N = 505;
int t, n1, n2, i, j, k;
double a1[N], a2[N], dp[N][N];

void tra() {
	if (n1 > n2) {
		for (int i = 1; i <= n1; i++) {
			double t = a1[i];
			a1[i] = a2[i];
			a2[i] = t;
		}
		int t = n1;
		n1 = n2;
		n2 = t;
	}
	k = n2 - n1;
}

int main() {
	scanf("%d", &t);
	while (t--) {
		double ans = INF;
		scanf("%d%d", &n1, &n2);
		for (i = 1; i <= n1; i++)
			scanf("%lf", &a1[i]);
		for (i = 1; i <= n2; i++)
			scanf("%lf", &a2[i]);
		tra();
		sort(a1 + 1, a1 + n1 + 1);
		sort(a2 + 1, a2 + n2 + 1);
		for (i = 1; i <= n1; i++) {
			double Min = INF;
			for (j = 0; j <= k; j++) {
				if (i + j > n2) break;
				Min = min(Min, dp[i - 1][j]);
				dp[i][j] = INF;
				dp[i][j] = min(dp[i][j], Min + fabs(a1[i] - a2[i + j]));
				if (i == n1)
					ans = min(ans, dp[i][j]);
			}
		}
		printf("%.1lf\n", ans);
	}
	return 0;
}