SOJ 1685 Chopsticks

来源:互联网 发布:时间序列预测算法编程 编辑:程序博客网 时间:2024/05/16 03:44

题意:有N支筷子,要求其中选出M套筷子,每一套筷子有A,B,C三支,并满足A<=B<=C,并称(AB)2为每套筷子的’badness’,现在要求这M套筷子的’badness’总和最少,求最少的总和是多少.

分析:现在我们先不考虑C,我们只考虑每套筷子只有两支,并使得’badness’总和最少应该满足什么条件, 现在我们假设有a1,a2,a3,a4四支筷子,并且a1<=a2<=a3<=a4,应该如何配套才能使’badness’最小呢.可以看出这里一共有A{{a1, a2}, {a3,a4}} , B{{a1, a3}, {a2, a4}} , C{{a1, a4}, {a2, a3}}三种配套方式,很明显badness(B) >= badness(A), 我们比较 badness(A)和badness(C)的大小关系, badness(A) - badness(C) = 2(a4-a2)(a1-a3) <= 0所以badness(A) <= badness(C). 所以可以推论只有所有配套的筷子都是相邻的两个才能使得总得badness最小. 此时我们便可以考虑背包来做,定义dp[i][j]表示前i个筷子,组成j双筷子的时候最小的badness值,则dp转移方程为dp[i][j] = min(dp[i-1][j], dp[i-2][j-1] + (a[i] - a[j])^2).
但是这道题每套筷子不止一双,还需要有一支C,怎么处理呢? 其实有一个很巧妙的办法,把C留出来就好了,可以这样处理,把筷子的长度从大到小排列

  for(int i = 1; i <= K; i++) {        for(int j = 3*i; j <= N; j++) {             dp[j][i] = min(dp[j-1][i], dp[j-2][i-1] + (A[j] - A[j-1])*(A[j] - A[j-1]));        }  }

外层需要表示第i套筷子,很明显要保证有足够的C留着配套,需要从 最后一双筷子必须要从3*i开始选,不然的话一定有双筷子A,B没有配套的C. 这样转移的话就可以保证了每双筷子都有了配套,很巧妙的处理方式!!

代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 5000 + 5;const int maxk = 1000 + 10;const int inf = 1<<30;int A[maxn];int dp[maxn][maxk];int K, N;int main(){    int T;    scanf("%d", &T);    while(T--) {        scanf("%d%d", &K, &N);        K += 8;        for(int i = N; i > 0; i--) {            scanf("%d", &A[i]);        }        for(int i = 0; i <= N; i++) {            dp[i][0] = 0;            for(int j = 1; j <= K; j++) {                dp[i][j] = inf;            }        }        for(int i = 1; i <= K; i++) {            for(int j = 3*i; j <= N; j++) {                dp[j][i] = min(dp[j-1][i], dp[j-2][i-1] + (A[j] - A[j-1])*(A[j] - A[j-1]));            }        }        printf("%d\n", dp[N][K]);    }    return 0;}
0 0
原创粉丝点击