您的当前位置:首页正文

uva10271选筷子DP

2024-11-30 来源:个人技术集锦

题目

n n n根长度不相同的筷子,现在有 K K K个人需要使用筷子,每个人需要三根筷子,一个人的贡献为短的两根筷子的差值的平方,即 ( A − B ) 2 (A-B)^2 (AB)2。求 K K K个人选完筷子的最小贡献和。

解题思路

如果每个人只选择两根筷子的话,题目就简单了不少。因为肯定会选择连续的两根筷子,也就是 n n n个排好序的数,选出 k k k对数贡献最小。那么就有

D P [ i ] [ 1 / 0 ] [ j ] DP[i][1/0][j] DP[i][1/0][j]为第 i i i个数,选、不选时,总共有 k k k对数的最小贡献。

则有状态转移方程:

//要选i-1和i这一对数 那么前一个数肯定不能选
DP[i][1][j] = min(DP[i][0][j], DP[i - 1][0][j]);

//不选i-1和i这一对数 那么前一个数可选可不选
DP[i][0][j] = min(DP[i][0][j], DP[i - 1][0][j]);
DP[i][0][j] = min(DP[i][0][j], DP[i - 1][1][j]);

题目要求每个人三根筷子,那么从大到小选,并且加上限制条件 j ∗ 3 < = i j*3<=i j3<=i 即可。

AC代码

#include <bits/stdc++.h>
using namespace std;

const int N = 5005, M = 1010;
int a[5010];
long long dp[N][2][M]; //第i根筷子 选/不选 凑出j双的方案数
void solve()
{
    memset(dp, 0x3f3f3f3f, sizeof dp);
    int k, n;
    scanf("%d %d", &k, &n);
    k += 8;
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    sort(a + 1, a + 1 + n, greater<int>());
    for (int i = 0; i <= 2; i++)
        dp[i][0][0] = 0;
    for (int i = 3; i <= n; i++)
    {
        for (int j = 0; j <= min(i / 3, k); j++)
        {
            if (j >= 1)
                dp[i][1][j] = min(dp[i][1][j], dp[i - 1][0][j - 1] + (a[i - 1] - a[i]) * (a[i - 1] - a[i]));
            dp[i][0][j] = min(dp[i][0][j], dp[i - 1][1][j]);
            dp[i][0][j] = min(dp[i][0][j], dp[i - 1][0][j]);
        }
    }
    cout << min(dp[n][0][k], dp[n][1][k]) << endl;
}
int main()
{

    int t;
    cin >> t;
    while (t--)
        solve();
    return 0;
}
显示全文