背包问题打印所选物品及最优解
把原本的 dp[]一维数组
改成 pair<int,int>dp[][]
dp[i][j]
第1维存储当前已选择的物品的个数
第2维存储当前花费的钱数(限制条件)
first存储当前条件所能取得的最大价值
second存储第i个物品的数量
dp[i][j].first=dp[i-1][j].first; //继承上一次的状态
dp[i][j].second=0; //数量先初始化为0
if(dp[i][j].first<dp[i-1][j-tt[i]].first+value[i])
{
dp[i][j].first=dp[i-1][j-tt[i]].first+value[i]; //如果是多重背包,需要考虑数量
dp[i][j].second=1; // 0 1背包时数量为1,多重背包需要数量为k
}
枚举限制条件寻找最优解
不仅可以求出最大的所得价值,也可以求出在所得最大价值得情况下,
所用得最少花费,然后利用最少花费进行回溯,可求出最优解
for(int i=1;i<=time;i++)// time是题目中所给的限制条件上限
{
if(dp[n][i].first==dp[n][time].first)//这样就能求出拿到最大价值之下,所用的最少花费
{
mmin=i;
break;
}
}
利用最少花费回溯出最优解
for(int i=n;i>=1;i--)//用一种回溯的方法求出 最优解的选择!!!!
{
ans[i]=dp[i][mmin].second;
mmin-=tt[i]; //如果是多重背包,这里 tt[i]需要乘上数量
}
for(int i=1;i<=n;i++)///所有物品的选择情况!!!!!!
{
cout<<ans[i]<<" ";
}
最长递增子序列优化及打印实际内容
未优化的:
for(int i=1;i<=n;i++)
{
dp[i]=1;
for(int j=1;j<i;j++)
if(a[j]<a[i])
dp[i]=max(dp[j]+1,dp[i]); //后面的状态继承前面的状态
ans=max(ans,dp[i]);
}
经过二分函数优化后的:
求最长上升子序列:
使用lower_bound函数
ans=1;
for(int i=1;i<=n;i++)
{
dp[i]=INF;
}
for(int i=1;i<=n;i++)
{
*lower_bound(dp+1,dp+1+n,a[i])=a[i];
}
ans=lower_bound(dp+1,dp+1+n,INF)-dp-1;
求最长不下降子序列
使用upper_bound函数
ans=1;
for(int i=1;i<=n;i++)
{
dp[i]=INF;
}
reverse(a+1,a+1+n);
for(int i=1;i<=n;i++)
{
*upper_bound(dp+1,dp+1+n,a[i])=a[i];
}
ans=upper_bound(dp+1,dp+1+n,INF)-dp-1;
打印最长上升子序列的“序号”
for(int i=1;i<=n;i++)
{
dp[i]=1; //先全部初始化成1
}
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
if(a[j]>a[i]&&dp[i]+1>dp[j])
{
dp[j]=dp[i]+1;
pre[j]=i; //用pre数组记录前置节点
}
}
}
int ans=1;
for(int i=1;i<=n;i++)
{
if(ans<dp[i])
{
ans=dp[i];
id=i; //记录最后一个人的编号!
}
}
int cnt=0;
res[++cnt]=id; //用res数组记录 所选的下标
while(pre[id])
{
res[++cnt]=pre[id]; //res存得就是所选 最长上升子序列的下标,需要逆序输出!
id=pre[id];
}
最长公共子序列及打印实际内容
最长公共子序列的长度
string a;
string b;
cin>>a>>b;
for(int i=0;i<a.size();i++){
for(int j=0;j<b.size();j++)
{
if(a[i]==b[j])
{
dp[i+1][j+1]=dp[i][j]+1;
}
else
dp[i+1][j+1]=max(dp[i+1][j],dp[i][j+1]);
}
}
打印所有的最长公共子序列
#include<bits/stdc++.h>
using namespace std;
int dp[505][505]; //动态规划表!
string a,b;
set<string> ans;
void print(int i,int j,string str)
{
while(i>0&&j>0)
{
if(a[i-1]==b[j-1])
{
str.push_back(a[i-1]);
i--;
j--;
}
else
{
if(dp[i-1][j]>dp[i][j-1])
{
i--;
}
else if(dp[i-1][j]<dp[i][j-1])
{
j--;
}
else
{
print(i-1,j,str);
print(i,j-1,str);
return ;
}
}
}
reverse(str.begin(),str.end());
ans.insert(str);
}
int main() {
cin>>a>>b;
for(int i=0; i<a.size(); i++) {
for(int j=0; j<b.size(); j++) {
if(a[i]==b[j]) {
dp[i+1][j+1]=dp[i][j]+1;
} else
dp[i+1][j+1]=max(dp[i+1][j],dp[i][j+1]);
}
}
int lenth=dp[a.size()][b.size()];
cout<<lenth<<endl;
string str;
print(a.size(),b.size(),str);
for(auto it:ans)
{
cout<<it<<endl;
}
return 0;
}
最长公共子串及打印实际内容
//未完待续
字符串中为“ABC”的子序列的个数
string s;
cin>>s;
int a=0,b=0,c=0;
for(int i=0;i<s.size();i++)
{
if(s[i]=='A')
a++;
else if(s[i]=='B')
b+=a;
else if(s[i]=='C')
c=(c+b)%1000000007;
}
cout<<c;