Chopsticks

在这里插入图片描述
题目要你求从n个筷子(升序)中选出k+8组,每组3个筷子且筷子大小要a<=b<=c,然后每组筷子中最短的两根(a-b)2表示为该组的值,求选出k+8组筷子时的最小值是多少。
那么很明显,筷子由于升序,若要两根筷子差的平方最小的时候,肯定是选择相邻的两根筷子,然后再选一根比前面两根大的作为第三根。
首先要将数据逆序,因为如果你顺序选择,有可能你选择两根筷子差的平方是最小了,但是却没有第三根比他们大的筷子来充当第三根筷子了
这个问题用DP来处理,状态转移方程为:dp(i,j)=min(dp(i,j-1),dp(i-1,j-2)+(a[j]-a[j-1])2);
i表示第几组,j表示在筷子中选择了第几根,dp(i,j)的含义为在第i组时,所有筷子中的第j根时,最小值为多少。
那么由此,我们可以知道,当处于第j根时有两种选择,
一种是作为整组筷子的第3根,那么d(i,j)明显等于d(i,j-1) (因为你都是第三根了,那你的值肯定是沿袭前一根的值)
一种是作为这一组最短的两根之一,那么当然dp(i,j)的答案就为:dp(i-1,j-2)+与前一根筷子差的平方。
然后对两种情况取min就是当前dp(i,j)的值了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<algorithm>
#include<bitset>
#define scand(a) scanf("%d",&a)
#define scandd(a,b) scanf("%d%d",&a,&b)
#define scanddd(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define mst(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&-x
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=5005;
int dp[maxn][maxn];
int main()
{
	#ifdef local
	freopen("1.txt","r",stdin);
	#endif
	int T;
	cin>>T;
	while(T--)
	{
		int chop[maxn];
		int n,m;
		scandd(n,m);
		for(int i=1;i<=m;i++)scand(chop[i]);
		sort(chop+1,chop+1+m,greater<int>());
		mst(dp,0x3f);
		for(int i=1;i<=m;i++)dp[0][i]=0;//易知不成一组时,值为0
		for(int i=1;i<=n+8;i++)
		{
			for(int j=i*3;j<=m;j++)
			{
				int sum=(chop[j-1]-chop[j])*(chop[j-1]-chop[j]);
				dp[i][j]=min(dp[i][j-1],dp[i-1][j-2]+sum);
			}
		}
		printf("%d\n",dp[n+8][m]);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值