动态规划常用技巧学习指南

前置芝士

悬线法

悬线法可以用来解决给定矩阵极大子矩阵问题。

能在O(nm) 时间内解决求给定矩阵中极大矩形(最大子矩形/子正方形)的问题。

可以应用于满足以下条件的题目:

  • 需要在扫描序列时维护单调的信息,比如某种最大值;
  • 可以使用单调栈解决;
  • 不需要在单调栈上二分。

单调队列优化DP

对于形如\(f[i]=\max(f[L\leq j\leq R]+w[i])\),即转移来自之前某一个定长区间的最值。我们常使用单调队列来维护区间最值,从而优化决策。

DAG上的DP

很多问题可以转化为DAG上的最长路,最短路或者路径计数问题

一个问题如果可以转化为典型的二元关系,二元关系可以用图来建模。

Journey

[problem description]

给出一个n个点m条边的有向无环图。
问从1到n,在距离不超过k的情况下最多经过多少点,并输出一个方案。

[input]

The first line of the input contains three integers $ n,m $ and $ T $ ( $ 2<=n<=5000,1<=m<=5000,1<=T<=10^{9} $ ) — the number of showplaces, the number of roads between them and the time of Irina's stay in Berlatov respectively.

The next $ m $ lines describes roads in Berlatov. $ i $ -th of them contains $ 3 $ integers $ u_{i},v_{i},t_{i} $ ( $ 1<=u_{i},v_{i}<=n,u_{i}≠v_{i},1<=t_{i}<=10^{9} $ ), meaning that there is a road starting from showplace $ u_{i} $ and leading to showplace $ v_{i} $ , and Irina spends $ t_{i} $ time units to pass it. It is guaranteed that the roads do not form cyclic routes.

It is guaranteed, that there is at most one road between each pair of showplaces.

4 3 13
1 2 5
2 3 7
2 4 8

[output]

Print the single integer $ k $ ( $ 2<=k<=n $ ) — the maximum number of showplaces that Irina can visit during her journey from showplace $ 1 $ to showplace $ n $ within time not exceeding $ T $ , in the first line.

Print $ k $ distinct integers in the second line — indices of showplaces that Irina will visit on her route, in the order of encountering them.

If there are multiple answers, print any of them.

3
1 2 4 

[solved]

[注意事项]

这题会卡空间,数组只能开int类型的。

[数组定义]

dp[i][j]代表从1节点出发,当前走到节点i,途径j个节点的最小代价

pre[i][j]代表从1节点出发,当前走到节点i,途径j个节点时,i节点的前驱

则满足dp[n][res]<=T的最大res即为所求,找出res后,倒序寻找前驱,再顺序输出结果即可

const int N=5010;
const int inf=0x3f3f3f3f;
int n,m,T;
int f[N][N],pre[N][N];
int res,ans[N],cnt;
struct edge{
	int u,v,w;
	void read(){
		cin>>u>>v>>w;
	}
}e[N];
//f[i][j]代表从1节点出发,当前走到节点i,途径j个节点的最小代价
void solve(){
	cin>>n>>m>>T;
	for(int i=1;i<=m;i++){
		e[i].read();
	}
	memset(f,0x3f,sizeof(f));
	f[1][1]=0;
	int u,v,w;
	for(int i=2;i<=n;i++){
		for(int j=1;j<=m;j++){
			u=e[j].u;
			v=e[j].v;
			w=e[j].w;
			if(f[v][i]>f[u][i-1]+w){
				f[v][i]=f[u][i-1]+w;
				pre[v][i]=u;
			}
		}
	}
	for(int i=n;i>=1;i--){
		if(f[n][i]<=T){
			res=i;
			break;
		}
	}
	cout<<res<<endl;
	for(int i=n;i!=1;i=pre[i][res--]){
		ans[cnt++]=i;
	}
	ans[cnt++]=1;
	for(int i=cnt-1;i>=0;i--) cout<<ans[i]<<" ";
	cout<<endl;
}
posted @ 2023-10-13 09:19  White_Sheep  阅读(7)  评论(0编辑  收藏  举报