目录
HDU1024 Max Sum Plus Plus(滚动数组)
HDU2859 Phalanx(最大对称矩阵)
【题意】
给一个矩阵,求这个矩阵的最大对称矩阵长度。
【解题思路】
设dp[i][j]为第(i,j)位置能够构成最大对称矩阵的长度。
当我们算到s[i][j]时,每次我们只需要将它上方的和右方的依次比较,看是否相同,注意这里不能只比较s[i-1][j]和s[i][j+1],因为可能出现不符合的情况,如:
zaba
cbab
abbc
cacq
当我们比较到红色的b的时候,如果只比较与他相邻的两个即绿色的b,就会从dp[i-1][j+1]多+1,而显然蓝色的部分不同。
当i!=0&&dp[i-1][j+1]>i-a时,dp[i][j]=dp[i-1][j+1]+1
当i!=0&&dp[i-1][j+1]<i-a (其中a为从当前位置找,找到的第一个不相等的x的位置,所以i-a就为最大的对称矩阵的长度)时,dp[i][j]=i-a;
当i==0时,dp[i][j]=1;
题解转自:https://blog.csdn.net/yangyafeiac/article/details/9445397
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+5;
char s[maxn][maxn];
int dp[maxn][maxn];
int main()
{
int n;
while(~scanf("%d",&n)&& n)
{
for(int i=0;i<n;i++)
scanf("%s",s[i]);
int ans=0;
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(i==0)dp[i][j]=1;
else
{
int a=i;
int b=j;
while(s[a][j]==s[i][b])
{
a--;
b++;
if(a<0 || b>=n)break;
}
if(dp[i-1][j+1]<i-a)dp[i][j]=dp[i-1][j+1]+1;
else dp[i][j]=i-a;
}
printf("dp[%d][%d]=%d\n",i,j,dp[i][j]);
ans=max(ans,dp[i][j]);
}
}
printf("%d\n",ans);
}
}
HDU1176 免费馅饼
【题意】
t秒x点掉馅饼。能不能接到看t-1秒gameboy是不是在x或x-1或x+1位置。最多可以得到多少馅饼。
【解题思路】
设dp[i][j]为第i秒在第j个位置能够得到的最大馅饼数。所以易得状态转移方程:
dp[i][j]=max(dp[i-1][j-1],dp[i-1][j],dp[i-1][j+1])+num[i][j]。(num[i][j]为第i秒在第j给位置能够得到的馅饼数)
然后就是注意初始化。也就是第1秒只能出现在4,5,6这三个位置,需要将dp[1][4],dp[1][5],dp[1][6]初始化一下,方便下面的操作。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int INF=0x3f3f3f3f;
int num[maxn][15],dp[maxn][15];
int main()
{
int n;
while(~scanf("%d",&n) && n)
{
memset(num,0,sizeof(num));
memset(dp,0,sizeof(dp));
int T=-INF,ans=-INF;
for(int i=0;i<n;i++)
{
int pos,t;
scanf("%d%d",&pos,&t);
T=max(T,t);
num[t][pos]++;
}
dp[1][5]=num[1][5];
dp[1][4]=num[1][4];
dp[1][6]=num[1][6];
for(int i=2;i<=T;i++)
{
for(int j=0;j<11;j++)
{
if(j==0)dp[i][j]=max(dp[i-1][j],dp[i-1][j+1]);
else if(j==10)dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]);
else dp[i][j]=max(dp[i-1][j],max(dp[i-1][j-1],dp[i-1][j+1]));
dp[i][j]+=num[i][j];
}
}
for(int i=0;i<11;i++)
ans=max(ans,dp[T][i]);
printf("%d\n",ans);
}
}
HDU1024 Max Sum Plus Plus(滚动数组)
【题意】
给一个长度为n的序列,将它分成m段,使这m段的和达到最大。
【解题思路】
设dp[i][j]表示选取第j个数字,将前j个数字分成i组的最大和。
那么易得:dp[i][j]=max(dp[i][j-1] , max(dp[i-1][0]...dp[i-1][j-1]) )+a[j]。
dp[i][j-1]:表示与前面的数一起构成1组。
max(dp[i-1][0]...dp[i-1][j-1]):表示与前面的数断开,自成一组。
为了不爆内存,需要用滚动数组优化一下,因为所有的状态只涉及dp[i][*]和dp[i-1][*],所以max( dp[i-1][k] ) 就是上一组 k(0....j-1) 的最大值。我们可以在每次计算dp[i][j]的时候记录下前j个的最大值用pre数组保存。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
const int INF=0x7fffffff;
int a[maxn],pre[maxn],dp[maxn];
int main()
{
int m,n;
while(~scanf("%d%d",&m,&n))
{
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int ans=-INF;
memset(dp,0,sizeof(dp));
memset(pre,0,sizeof(pre));
for(int i=1;i<=m;i++)
{
ans=-INF;
for(int j=i;j<=n;j++)//因为当前计算的是第i组,所以j最小为i
{
dp[j]=max(dp[j-1],pre[j-1])+a[j];
pre[j-1]=ans;
ans=max(ans,dp[j]);
}
}
printf("%d\n",ans);
}
}