给我们n个硬币
每个硬币都有它的面值,要我我们分为两堆硬币,使得硬币的差值最小
我们可以dp计算出所有的差值,然后从小到大枚举差值,如果差值存在,就输出
dp[i][j] 表示对于前i件物品能达到差值j
状态转移方程为 if(dp[i-1][j]==1) dp[i][j] = 1(不选第i个物品),dp[i][abs(j-2*a[i])] = 1(选第i件物品)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
typedef long long LL;
const int INF = <<;
/* */
const int N = + ;
int a[N];
int dp[N][+];//dp[i][j] 表示对于对于前i个物品,差值为j是否存在, 然后算出所有可能的差值
int main()
{
int t, n, i, j, sum;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
sum = ;
for (i = ; i <= n; ++i)
{
scanf("%d", &a[i]);
sum += a[i];
} memset(dp, , sizeof(dp)); dp[][sum] = ;
for (i = ; i <= n; ++i)
{
for (j = ; j <= sum; ++j)
{
if (dp[i - ][j])
{
dp[i][j] = ;
dp[i][abs(j - * a[i])] = ;
}
}
}
for (j = ; j <= sum; ++j)//从小到大枚举差值
if (dp[n][j])
break;
printf("%d\n", j);
}
return ;
}
http://ncc.neuq.edu.cn/oj/problem.php?id=1457
t 数据组数
n k k表示最多能交换k个数字
n个数字 -100<=数字<=100
n个数字
问我们最多交换k次两堆数字中对应的数字,问我们能达到的最小差值,
我们可以计算出第一堆数据所能达到的所有状态,并记录其交换的次数
dp[i][j] = k 表示对于前i个数字,交换了k次,能达到状态j
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
typedef long long LL;
const int INF = <<;
/* */
const int N = + ;
int a[N], b[N];
int dp[N][ + ];//dp[i][j] 表示前i件物品,能使得陈船长的好玩度为j
int main()
{
int t, n, k, i, j;
int sum;
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, &k);
sum = ;
for (i = ; i <= n; ++i)
{
scanf("%d", &a[i]);
a[i] += ;
sum += a[i];
}
for (i = ; i <= n; ++i)
{
scanf("%d", &b[i]);
b[i] += ;
sum += b[i];
} for (i = ; i <= n; ++i)
for (j = ; j <= sum; ++j)
dp[i][j] = INF;
dp[][a[]] = ;
dp[][b[]] = ;
for (i = ; i <= n; ++i)
{
for (j = ; j <= sum; ++j)//算出第一堆数字总和达到j需要的交换次数
{
if (j >= a[i])//不交换第i个数字, j-a[i]为上一层所能达到的总和
dp[i][j] = min(dp[i][j], dp[i-][j - a[i]]);
if (j >= b[i])//交换第i个数字,j-b[i]为上一层所能达到的总和
dp[i][j] = min(dp[i][j], dp[i-][j - b[i]] + );
}
}
int ans = INF;
for (i = ; i <= sum; ++i)
{
if (dp[n][i] <= k)
ans = min(ans, abs(sum - * i));
}
printf("%d\n", ans);
}
return ;
}