njupt 1581 筷子 DP

本文探讨了一个有趣的筷子配对问题,通过动态规划求解最小长度差平方和。问题描述了A先生需要从N根长度不等的筷子中选出K+3双,使筷子长度差的平方和最小。文章提供了完整的代码实现,包括初始化和状态转移方程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1581

比赛描述

A 先生有很多双筷子。确切的说应该是很多根,因为筷子的长度不一,很难判断出哪两根是一双的。这天,A 先生家里来了K 个客人,A 先生留下他们吃晚饭。加上A 先生,A夫人和他们的孩子小A,共K+3个人。每人需要用一双筷子。A 先生只好清理了一下筷子,共N 根,长度为T1,T2,T3,……,TN。现在他想用这些筷子组合成K+3 双,使每双的筷子长度差的平方和最小。(怎么不是和最小??这要去问A 先生了,呵呵)

输入共有两行,第一行为两个用空格隔开的整数,表示N,K(1≤N≤100,0<K<50),第二行共有N个用空格隔开的整数,为Ti每个整数为1~50之间的数。

输出仅一行。如果凑不齐K+3双,输出-1,否则输出长度差平方和的最小值。

思考:1. 关键是找到递推公式,f(i, j) = min{ f(i-1, j), f(i-2, j-1) + (len[i]-len[i-1])^2 } 这个公式中i j都是增加的。

            2.在计算过程中,初值很重要,这里应该是没有办法实现的时候,就是穷大。另外还要注意先计算什么,再
计算什么。

           3 dp[N][K]={INT_MAX}这个实际上是给第一个赋值最大,其余的为o

            4 还有使用memset是以字节为单位,初始化内存块。当初始化一个字节单位的数组时,可以用memset把每个数组单元初始化成任何你想要的值。如果是二维数组,赋值不成功。

memset函数的初始化只能对一维数组,对于每一行,是连续分配的; 然而对于各行之间,却不是连续非配的,容易出错

#include<cstdio>
#include<algorithm>
#include<ctime>
#include<iostream>
#include<cmath>
#include<string.h>
using namespace std;
#define N 105
#define K 60

int main() {
	int dp[N][K];//注意,这样只给第一个赋值最大,其余为0
	int a[N];
	int k,n,kk,tn;
	scanf("%d",&n);
	scanf("%d",&k);
	kk=k+3;
	tn=0;
	//memset(dp,10,sizeof(dp));
	for (int i = 0; i <= n; i++)
		for (int j = 0; j <= k + 3; j++)
			dp[i][j] = 1000;

	while(tn<n) {
		scanf("%d",&a[tn++]);
	}
	if(n<2*kk) {
		cout<<-1<<endl;
		return 0;
	}
	sort(a,a+n);

	dp[0][0]=0;
	for(int i=2; i<=n; i++)
		for(int j=1; j<=kk; j++) {
			//f(i, j) = min{ f(i-1, j), f(i-2, j-1) + (len[i]-len[i-1])^2 }
			int tt=dp[i-2][j-1]+(a[i-1]-a[i-2])*(a[i-1]-a[i-2]);
			dp[i][j]=min(tt,dp[i-1][j]);
		}
	cout<<dp[n][kk]<<endl;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值