想了一晚上加一上午,总算是给做出来了,还是1Y.
还是跟前面的几道题有些相似。
dp[i][j]表示前i个客人使用第j支与第j-1支筷子作为短筷子时的烂度。
很明显三元组中两只短筷子一定是相邻的,长筷子则不一定。
用降序做会比较好。
p[i][j]表示dp[i][j]对应状态可使用的长筷子。
状态转移方程:
如果p[i-1][j-2]>1则说明可以使用第j支与第j-1支筷子作为短筷子 此时dp[i][j]=min(dp[i-1][j-2]+badness,dp[i-1][j])分别表示使用和不使用
如果不能,则dp[i][j]=dp[i-1][j] 不使用第j支与第j-1支筷子作为短筷子
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define INF 0x7f7f7f7f
using namespace std;
int ch[5005];
int dp[1005][5005];
int p[1005][5005];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int K,N;
scanf("%d%d",&K,&N);
K=K+8;
memset(dp,0,sizeof(dp));
memset(p,0,sizeof(p));
for(int i=N; i>0; --i)
scanf("%d",&ch[i]);
for(int i=1; i<=N; ++i)
p[0][i]=i;
for(int i=1; i<=K; ++i)
{
for(int j=1; j<=N; ++j)
{
if(j<3*i-1)
{
dp[i][j]=INF;
p[i][j]=j;
}
else
{
if(p[i-1][j-2]>0)
{
int ld=(ch[j]-ch[j-1])*(ch[j]-ch[j-1]);
if(dp[i-1][j-2]+ld<dp[i][j-1])
{
dp[i][j]=dp[i-1][j-2]+ld;
p[i][j]=p[i-1][j-2]-1;
}
else
{
dp[i][j]=dp[i][j-1];
p[i][j]=p[i][j-1]+1;
}
}
else
{
dp[i][j]=dp[i][j-1];
p[i][j]=p[i][j-1]+1;
}
}
}
}
printf("%d\n",dp[K][N]);
}
return 0;
}
网上的题解和我的思路基本一致,不过没有用p[][]这个数组。代码修改后如下。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define INF 0x7f7f7f7f
using namespace std;
int ch[5005];
int dp[1005][5005];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int K,N;
scanf("%d%d",&K,&N);
K=K+8;
memset(dp,0,sizeof(dp));
for(int i=N; i>0; --i)
scanf("%d",&ch[i]);
for(int i=1; i<=K; ++i)
{
for(int j=1; j<=N; ++j)
{
if(j<3*i)
dp[i][j]=INF;
else
{
int ld=(ch[j]-ch[j-1])*(ch[j]-ch[j-1]);
dp[i][j]=min(dp[i-1][j-2]+ld,dp[i][j-1]);
}
}
}
printf("%d\n",dp[K][N]);
}
return 0;
}