首页 > 其他分享 >线性DP

线性DP

时间:2024-02-17 15:57:49浏览次数:22  
标签:const int DP ans 线性 include dp

这篇主要涉及线性DP。

先介绍给模型,求最长上升子序列。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=1020; 
int n;
int f[N],ans,a[N];
int pre[N],te;
void output(int x)
{
	if(x==0)
	{
		return;
	}
	
	output(pre[x]);
	cout<<a[x]<<" ";
}
int main()
{	 
	int x=0;
	while(scanf("%d",&x)!=EOF)
	{
		n++;
		a[n]=x;
	}
	for(int i=1;i<=n;i++)
	{
		f[i]=1;
		for(int j=1;j<i;j++)
		{
			if(a[i]>a[j]&&f[i]<f[j]+1)
			{
				f[i]=f[j]+1;
				pre[i]=j;
				if(ans<f[i])
				{
					ans=f[i];
					te=i;
				}
			}
		}
	
		
	}
	cout<<"max="<<ans<<endl;
	output(te);
	return 0;
}

其中也涉及了之前背包所用的路径标记。

下面来两个例题

拦截导弹

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=1020; 
int n;
int f[N],ans,cnt,num,a[N],b[N];
int pre[N],te;
int main()
{	 
	int x;
	while(scanf("%d",&x)!=EOF)
	{
		cnt++;
		a[cnt]=x;
	} 
	for(int i=1;i<=cnt;i++)
	{
		f[i]=1;
		for(int j=1;j<=cnt;j++)
		{
			if(a[i]<=a[j]&&f[i]<f[j]+1)
			{
				f[i]=f[j]+1;
			}
		}
		ans=max(ans,f[i]);
	} 
	for(int i=1;i<=cnt;i++)
	{
		b[i]=1;
		for(int j=1;j<i;j++)
		{
			if(a[i]>a[j])
			{
				b[i]=max(b[i],b[j]+1);
			}
		}
		num=max(num,b[i]);
	 } 
	cout<<(ans+1)/2<<endl<<num;
}

飞翔

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=1500;
const int Inf=0x3f3f3f3f;
int dp[maxn];
int sum;
double ans;
struct node
{
	int x,y;
}a[maxn];
bool cmp(node a,node b)
{
	return a.x<b.x;
}
int main()
{
	int n,m,k;
	cin>>n>>m>>k;
	for(int i=1;i<=k;i++)
	{
		cin>>a[i].x>>a[i].y;
	}	
	sort(a+1,a+k+1,cmp);
	for(int i=1;i<=k;i++)
	{
		for(int j=i+1;j<=k;j++)
		{
			if(a[j].x>a[i].x && a[j].y>a[i].y && dp[i]+1>dp[j])
			dp[j]=dp[i]+1;
		}
			
	}
		
	for(int i=1;i<=k;i++)
	{
		sum=max(dp[i],sum);	
	}	
	sum++;
	double len=2-sqrt(2);
	ans=(m+n-sum*len)*100;
	printf("%.0lf",ans); 
	return 0;
}

还算简单吧,接下来步入正题,看看真正的线性DP。

1.与图论相关联的线性DP

挖地雷

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=250; 
int n;
int f[N],ans,cnt,num,a[N],b[N];
int pre[N],g[N][N],s[N],flag[N];
int main()
{	 
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		f[i]=a[i];
		ans=max(ans,f[i]); 
	}
	int x,y;
	while(1)
	{
		cin>>x>>y;
		 
		if(x==0&&y==0)
		{
			break;
		}
		g[x][y]=1;//利用邻接矩阵存储有向图 
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(g[i][j]==1)
			{
				if(f[j]<f[i]+a[j]) 
				{
					f[j]=f[i]+a[j]; 
					s[j]=i;//追踪 
				}
				ans=max(ans,f[j]);	
			}
		}	
	}
	int m=ans;
	for(int i=1;i<=n;i++)
	{
		if(m==f[i])//标记 
		{
			m=i;
			break;
		}
	}
	while(m)
	{
		
		flag[m]=1;
		m=s[m];
		if(m==s[m])
		{
			break;
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(flag[i]==1&&cnt==0)//遍历 
		{
			cout<<i;
			cnt=1;
		}
		else if(flag[i]==1)
		{
			cout<<"-"<<i;
		}
	}
	cout<<endl;
	cout<<ans;
}

注意同样的标记路径法

2.贪心的线性DP
只是与贪心算法类似,但并不能等同于贪心。

奶牛渡河(也不知道为什么这么喜欢奶牛)

点击查看代码
#include<bits/stdc++.h> 
using namespace std;
const int N=2600;
int n,m,ans=1000000;
int f[N],a[N],s[N];
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		s[i]=s[i-1]+a[i]; 
	}
	for(int i=1;i<=n;i++)
	{
		f[i]=s[i]+m;
		for(int j=1;j<i;j++)
		{
			f[i]=min(f[i],f[j]+f[i-j]+m);
		}
	} 
	cout<<f[n];
}

打鼹鼠

点击查看代码
#include<bits/stdc++.h>
using namespace std;

#define N 10005
int n, m, ti, x, y, dis,ans;
int dp[N];
struct mouse{
	int ti, x, y;
}mi[N];
int l(mouse a, mouse b);
int main(){
	cin >> n >> m;
	for(int i=1; i<=m; i++){
		cin >> mi[i].ti >> mi[i].x >> mi[i].y;
		dp[i] = 1;
	}
	for(int i=1; i<=m; i++){
		
		for(int j=i+1; j<=m; j++){
			int len = l(mi[i], mi[j]);
			if(len <= mi[j].ti - mi[i].ti){
				dp[j] = max(dp[j], dp[i] + 1);
				ans=max(ans,dp[j]);
			}
		}
		
	}
	cout << ans;
	return 0;
}

int l(mouse a, mouse b){
	return abs(a.x - b.x) + abs(a.y - b.y);
}

总结
这些题都没什么好说的,只要能找对状态转移方程就很好理解。
因此在线性DP中最主要的地方就在于找出状态转移方程(无它,唯手熟耳,多练练题,就容易搞懂)。
线性DP就到这里了,拜拜

标签:const,int,DP,ans,线性,include,dp
From: https://www.cnblogs.com/zhengchenxi/p/18018031

相关文章

  • 区间dp
    区间dp区间dp属于线性dp的一种,以“区间长度”作为dp的“阶段”,用两个坐标(区间的左、右端点)描述每个维度。区间dp中,一个状态往往由若干个比它更小且包含于它的区间所代表的阶段转移而来,所以区间dp的决策往往就是划分dp的方法。典型例题:石子合并for(inti=1;i<=n;i++)f[i][i]=......
  • 五大基础dp
    动规条件•最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。•无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。•有重叠子问题:即子问题之......
  • 背包dp
    01背包:所谓01背包,就是每种物体有一个价值且数量只有一个,给定一个背包容量,在不超出背包容量的前提下在n个物体中取m个,求最大价值。点击查看代码//f[i]指体积为i时的最大价值for(inti=1;i<=n;i++){//第一层循环是指遍历每种物体,n是物体种数 for(intj=m;j>=v[i];j--){//第......
  • 背包DP
    下面介绍一下背包DP主要题型基础模型(没什么好说的,上模板)1.01背包最主要的模板,应用很多,很重要!!!倒着遍历容积,不会受后选小的f[i][j]影响,已经选过的物品不会再选一遍。点击查看代码#include<bits/stdc++.h>usingnamespacestd;constintN=10020;intf[N];intn,m;intv......
  • 关于动态规划(Dynamic Programming)的若干思考 ------ [1.背包dp]
    背包dp;1.01背包(1)领域展开#include<bits/stdc++.h>//simpleusingnamespacestd;constintmaxm=2024;intn,m;intw[maxm],v[maxm],f[maxm][maxm];intmain(){ cin>>n>>m; for(inti=1;i<=n;i++) cin>>v[i]>>w[i]; for(i......
  • 背包dp
    1、01背包f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i])二维为背包现有容量,一维为前i个物品表示在前i个物品所能选取的最大价值在判断第i个的最大值时要由前一个的状态转移过来;即下一层的状态由上一层转移来;可以直接省掉第一维(压维),从后往前更新过来,若还是正序就会出现一种情况......
  • dp的优化(单队,斜率)
    1.单调队列优化\(dp\)维护最小值:\(x\leqslantq.tail()\)维护最大值:\(x\geqslantq.tail()\)其实原理不难,当\(dp\)的转移源头是一个区间时,往往使用单调队列来维护区间最值(一般队列里装下标以方便维护区间大小,但也只是一般情况),节省了处理区间的时间(甚至噶掉一维),重点是对区间的......
  • 树状DP心得
    说一下近日所学的主要两种题型,一个是分叉情况问题,一种是树上背包问题。分叉情况问题具体的题可以参考小胖守皇宫和三色二叉树。点击查看代码小胖守皇宫#include<bits/stdc++.h>usingnamespacestd;constintN=2000;vector<int>son[N];intfa[N],h[N],f[N][3];//f[0]......
  • 机器学习中7种常用的线性降维技术总结
    上篇文章中我们主要总结了非线性的降维技术,本文我们来总结一下常见的线性降维技术。1、PrincipalComponentAnalysis(PCA)PrincipalComponentAnalysis(PCA)是一种常用的降维技术,用于将高维数据集转换为低维表示,同时保留数据集的主要特征。PCA的目标是通过找到数据中最大......
  • DPInst64.exe difxapi64.dll 是什么 为什么
    DPInst64.exe:安装和卸载驱动程序包。默认情况下,该工具将搜索当前目录,并尝试安装找到的所有驱动程序包。用法:C:\Users\Administrator\Desktop\dp\dp\DPInst64.exe[/UINF文件][/S|/Q][/LM][/P][/F][/SH][/SA][/A][/PATH路径][/EL][/L语言ID][/C][/D][/LogTitle标题][/SW][/?......