UVa 10271 - Chopsticks (dp)

题目链接:https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=14&page=show_problem&problem=1212

首先发现,最短的两只筷子一定是相邻的,如果不是,换成相邻的答案一定更优

考虑如果没有最长的筷子,那么设 \(dp[i][j]\) 表示前 \(i\) 只筷子组成了 \(j\) 套筷子,每只筷子有选或不选两种决策

而现在有最长的筷子这个限制,我们可以考虑将筷子长度从大到小排序,这样每套筷子中最长的一根,在当前决策时已经选择过了,因为长度大于等于最短的两根筷子,这样就不需要特殊考虑了

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

const int maxn = 5010;

int T, n, k; 
int a[maxn];
int dp[maxn][maxn];

bool cmp(int x, int y){
	return x > y; 
}

int sqr(int x){
	return x * x;
}

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	scanf("%d", &T);
	while(T--){
		scanf("%d%d", &k, &n);
		for(int i = 1 ; i <= n ; ++i) scanf("%d", &a[i]);
		sort(a + 1, a + 1 + n, cmp);
		
		memset(dp, 0x3f, sizeof(dp));
		dp[0][0] = 0;
		for(int i = 1 ; i <= n ; ++i){
			for(int j = 0 ; j <= min(i/3, k + 8) ; ++j){
				dp[i][j] = min(dp[i][j], dp[i-1][j]);
				if(i >= 2 && j >= 1) dp[i][j] = min(dp[i][j], dp[i-2][j-1] + sqr(a[i]-a[i-1]));
			}
		}
		printf("%d\n", dp[n][k+8]);
	}
	return 0;
}
posted @ 2021-07-31 20:32  Tartarus_li  阅读(35)  评论(0编辑  收藏  举报