TZOJ:5752
循环遍历第一个字符串和第二个字符串,如果第一个字符串的第i个位置与第二个字符串的第j个位置是相同的,那么dp【i】【j】就是dp【i-1】【j-1】+1。如果不同就是从dp【i-1】【j】和dp【i】【j-1】中取最大,最后dp【n-1】【m-1】就是答案
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int m,n,dp[N][N];
string a,b;
signed main()
{
cin>>a>>b;
n=a.size();
m=b.size();
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(a[i]==b[j])
{
dp[i+1][j+1]=dp[i][j]+1;
}
else dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]);
}
}
cout<<dp[n][m]<<endl;
}
TZOJ:8542
因为子串必须要是连续的,所以整体做法和上面相同,只是在不同的时候要赋值0,而不是从dp【i-1】【j】和dp【i】【j-1】里选择一个较大值。
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int m,n,dp[N][N];
string a,b;
signed main()
{
cin>>a>>b;
n=a.size();
m=b.size();
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(a[i]==b[j])dp[i+1][j+1]=dp[i][j]+1;
else dp[i+1][j+1]=0;
}
}
int Max=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)Max=max(Max,dp[i][j]);
cout<<"max="<<Max<<endl;
}
TZOJ:1072
用一个二维dp数组记录编辑距离,还是循环遍历两个字符串,相同的时候编辑距离就是dp【i-1】【j-1】,不同的时候要从删除,插入和修改里选择一个最优的操作。
修改:dp【i-1】【j-1】+1
删除:dp【i-1】【j】+1和dp【i】【j-1】+1
插入:dp【i-1】【j】+1和dp【i】【j-1】+1
所以不同的时候就是从dp【i-1】【j-1】,dp【i-1】【j】+1和dp【i】【j-1】+1选择较小的值
最后输出dp【n-1】【m-1】即可。
初始化的时候遍历dp【i】【0】和dp【0】【j】的时候要初始化为i和j,因为一个空的字符串要和另一个字符串相同显然要插入另一个字符串长度的数量。
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+100;
string a,b;
int n,m,dp[N][N];
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
while(cin>>a>>b)
{
n=a.size();m=b.size();
memset(dp,0,sizeof(dp));
for(int i=0;i<=n;i++)dp[i][0]=i;
for(int i=0;i<=m;i++)dp[0][i]=i;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i-1]==b[j-1])dp[i][j]=dp[i-1][j-1];
else dp[i][j]=min(dp[i-1][j]+1,min(dp[i][j-1]+1,dp[i-1][j-1]+1));
}
}
cout<<dp[n][m]<<endl;
}
}
TZOJ:8484
这题我把他看成青蛙跳台阶去偷,dp【i】用来记录到第i个房屋的时候能偷到的最大金额,偷到第j个房屋时,第j+1就不能偷,因此要去偷第j+2个,也可以直接偷第j+3个,这样就和前面那一种方法是不一样的。如果偷第j+4个,就不是最优的方法了,因为第j+4个是可以从第j+2个过来的,直接去第j+4个反而不是最优了,最后输出dp【n-1】和dp【n】的较优解即可。
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+100;
int n,m,dp[N],a[N];
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
memset(dp,0, sizeof(dp));
dp[1]=a[1];
dp[2]=a[2];
for(int i=3;i<=n;i++)
dp[i]=max(dp[i-2],dp[i-3])+a[i];
cout<<max(dp[n],dp[n-1])<<endl;
}
TZOJ:8500
由于每天只能持有一股股票,所以不能在每次低价的时候进行购买屯票再在高价的时候卖出,因此我要选择在第i天时对于第i天的利润最优的方法。
用dp【i】【0】和dp【i】【1】来表示第i天持有股票和未持有股票时的最大金额。
那么dp【i】【0】就可以从dp【i-1】【1】+a【i】和dp【i-1】【0】转换过来
dp【i】【1】从dp【i-1】【0】-a【i】和dp【i-1】【1】转换过来。
这样就做到了当前状态的最优,dp【n】【0】就是最终的答案。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,dp[N][5],a[N];
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
dp[1][0]=0;dp[1][1]=-a[1];
for(int i=2;i<=n;i++)
{
dp[i][1]=max(dp[i-1][1],dp[i-1][0]-a[i]);
dp[i][0]=max(dp[i-1][0],dp[i-1][1]+a[i]);
}
cout<<dp[n][0]<<endl;
}
TZOJ:8502
跟前一题一样,但是增加了买卖次数限制,意味着只能买k次。
那就让dp多一维,变成dp【i】【j】【0|1】表示在第i天进行了j次购买后,持有股票时和未持有股票时的最优利润。
dp【i】【j】【0】由dp【i-1】【j】【0】和dp【i-1】【j】【1】+a【i】转换。
dp【i】【j】【1】由dp【i-1】【j】【1】和dp【i-1】【j-1】【0】-a【i】转换。
dp【0】【j】【1】为非法状态,初始化为负的最大值。
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int n,a[N],k,dp[N][N][2];
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=0;i<=k;i++)dp[0][i][1]=-1e6;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=k;j++)
{
dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]+a[i]);
dp[i][j][1]=max(dp[i-1][j][1],dp[i-1][j-1][0]-a[i]);
}
}
int Max=0;
for(int i=0;i<=k;i++)Max=max(Max,dp[n][i][0]);
cout<<Max<<endl;
}
TZOJ:8503
还是三维dp
dp【i】【0|1】【0|1】表示第i天是否有买卖冷却,是否持有股票。
那么dp【i】【0】【0】就由dp【i-1】【0】【0】和dp【i-1】【1】【0】转换。
dp【i】【1】【0】就由dp【i-1】【0】【1】+a【i】转换。
dp【i】【0】【1】就由dp【i-1】【0】【0】-a【i】以及dp【i-1】【0】【1】转换。
dp【i】【1】【1】由于表示的时候有冷却以及手上有票,但是有冷却的时候说明第i天已经卖出股票了,然后又把当天的股票买回来,算是非法的操作,所以就不用管。
初始化dp【0】【0】【0】为合法,初始化为0,dp【0】【0】【1】和dp【0】【1】【0】非法,初始化负的最大值。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,a[N],k,dp[N][2][2];
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
dp[0][0][1]=-1e6;
dp[0][1][1]=-1e6;
for(int i=1;i<=n;i++)
{
dp[i][0][0]=max(dp[i-1][0][0],dp[i-1][1][0]);
dp[i][0][1]=max(dp[i-1][0][1],dp[i-1][0][0]-a[i]);
dp[i][1][0]=dp[i-1][0][1]+a[i];
}
cout<<max(dp[n][1][0],dp[n][0][0])<<endl;
}