背包问题打印及线性DP打印

背包问题打印所选物品及最优解

把原本的 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;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值