给定 n 个实数,把它们划分为元素和尽量接近、但不相交的两个子集,用C语言实现
时间: 2024-05-25 21:17:34 浏览: 150
这是一个NP完全问题,可以使用动态规划解决。
首先,计算所有数的和 sum,然后将问题转化为一个背包问题:在 n 个物品中选择一些物品,使得它们的和最接近 sum/2,但不能超过 sum/2。
设 dp[i][j] 表示在前 i 个物品中选择一些物品,使得它们的和最接近 j,但不能超过 j。则有状态转移方程:
dp[i][j] = max(dp[i-1][j], dp[i-1][j-a[i]] + a[i])
其中 a[i] 表示第 i 个数的值。最终的答案即为 sum - 2 * dp[n][sum/2]。
以下是完整的 C 代码实现:
#include <stdio.h>
#include <stdlib.h>
#define MAXN 1005
int n;
double a[MAXN];
int dp[MAXN][200005];
int cmp(const void *a, const void *b) {
return *(double *)a < *(double *)b ? -1 : 1;
}
int main() {
scanf("%d", &n);
double sum = 0;
for (int i = 1; i <= n; i++) {
scanf("%lf", &a[i]);
sum += a[i];
}
qsort(a + 1, n, sizeof(double), cmp);
int target = (int)(sum / 2);
for (int i = 1; i <= target; i++) dp[0][i] = -1;
for (int i = 1; i <= n; i++) {
for (int j = target; j >= 0; j--) {
if (j >= a[i] && dp[i-1][j-a[i]] >= 0) {
dp[i][j] = dp[i-1][j-a[i]] + 1;
} else {
dp[i][j] = dp[i-1][j];
}
}
}
printf("%.1f", sum - 2 * target + 2 * dp[n][target]);
return 0;
}
阅读全文