【题解】hdu5693 D Game 区间DP

题目链接
在这里插入图片描述
在这里插入图片描述


区间DP好题,把区间DP的基本操作都用上了。(状态转移方程很多,见代码吧)

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
const int N=310;
int t,n,m,a[N],d,dp[N][N],f[N];
bool can[N][N];
map<int,int>mp;
int main()
{
	//freopen("in.txt","r",stdin);
    scanf("%d",&t);
    while(t--)
    {
    	memset(f,0,sizeof(f));memset(can,0,sizeof(can));memset(dp,0,sizeof(dp));
		scanf("%d%d",&n,&m);mp.clear();
    	for(int i=1;i<=n;i++)
    	    scanf("%d",&a[i]);
    	for(int i=1;i<=m;i++)
    	    scanf("%d",&d),mp[d]=1;
    	for(int i=1;i<=n;i++)
    	    for(int j=i+1;j<=n;j++)
    	    	if(mp[a[j]-a[i]])can[i][j]=1;
		for(int len=1;len<=n;len++)
		    for(int l=1;l+len<=n;l++)
		    {
		    	int r=l+len;
		    	dp[l][r]=max(dp[l+1][r],dp[l][r-1]);//区间DP基操 
		    	if(can[l][r]&&dp[l+1][r-1]==(r-l-1))
				    dp[l][r]=max(dp[l][r],dp[l+1][r-1]+2);//如果端点构成等差,且中间取空了 
		    	for(int i=l;i<r;i++)//枚举分点,DP基操 
		    	    dp[l][r]=max(dp[l][r],dp[l][i]+dp[i+1][r]);
		    	for(int i=l+1;i<r;i++)
		    	{
		    		if(can[l][i]&&dp[l+1][i-1]==(i-l-1))//如果左边构成等差且左边取空了 
		    		    dp[l][r]=max(dp[l][r],dp[l+1][i-1]+dp[i+1][r-1]+2);
		    		if(can[i][r]&&dp[i+1][r-1]==(r-i-1))//如果右边构成等差且右边取空了 
		    		    dp[l][r]=max(dp[l][r],dp[l][i-1]+dp[i+1][r-1]+2);
		    		if(can[l][i]&&can[i][r]&&(a[i]-a[l]==a[r]-a[i])&&dp[l+1][i-1]==(i-l-1)&&dp[i+1][r-1]==(r-i-1))
		    		//左中右构成等差,且左中右取空了
					    dp[l][r]=max(dp[l][r],r-l+1); 
				}
			}
		int ans=0;
		for(int i=1;i<=n;i++)
		    for(int j=1;j<=i;j++)
		        f[i]=max(f[i],f[j-1]+dp[j][i]),ans=max(ans,f[i]);
		printf("%d\n",ans);
	}
	return 0;
}

总结

区间DP好好好题

猜你喜欢

转载自blog.csdn.net/qq_41958841/article/details/83104212