动态规划之状态机

小b和排序
原题链接

【题目描述】

小b有两个长度都为n的序列A,B。

现在她需要选择一些i,然后交换A[i]和B[i],使得A和B都变成严格递增的序列。

你能帮小b求出最少交换次数吗?

输入保证有解。

输入
第一行输入一个正整数n,表示两个数组的长度;
第二行输入n个数,表示A[i],以空格隔开;
第三行输入n个数,表示B[i],以空格隔开;
其中1≤n≤1000, 0≤A[i],B[i]≤2000
输出
输出一个数,表示交换次数
输入样例
4
1 3 5 4
1 2 3 7
输出样例
1

【题解分析】

本题的状态比较少,我们可以考虑使用状态机的解法来分析这个题目。我们假设知道之前所有的最优解,即到第i 步让2个序列都严格递增的最少交换次数,那么每加入一对新的Ai,Bi ,只有换与不换2 种情况。我们用f[i][0] 表示第 i位不换,保持递增的最少交换次数, f[i][1] 表示第i 位交换,保持递增的最少交换次数.

如何才能想到这样的状态设置呢?
这才是动归该认真思考的。一般而言,就像小学解应用题设置未知数x一样,问什么设什么。既然问保持递增的最少交换次数,那我们就设f[i]为从1到i保持递增的最小交换次数,这样我们只要一层for循环求出f[n]记为所求。
但是继续思考发现f[i]与f[i-1]之间没有线性关系,进而想到使用状态机来表示第i位的状态。最后分析出上面的状态定义。

状态机理解

我们用示意图来表示状态之间的转移,这样很直接且好理解。状态机模式

  1. 状态定义

我们考虑当前第i位是否被交换,那么当前有两种状态0和1,对应上图的两个圆圈。那么接下来考虑上一个状态如何到达当前状态,对应上图中的箭头;

2.状态转移分析

扫描二维码关注公众号,回复: 12331657 查看本文章

从题意可知,对于f[i][0]这一状态而言,可以到达该状态有两种情况。第一种第i-1位不换,对应箭头1,那么对于箭头1的状态转换的条件是原序列已经保持递增,即a[i]>a[i-1]&&b[i]>b[i-1];第二种情况 第i-1位交换,对应箭头3,且交换之后保持递增,即a[i]>b[i-1]&&b[i]>a[i-1];
同理,可以推理得出对于状态f[i][1],可以到达该状态也有两种情况。分别对应箭头2,4;
综上所述,我们求得就是第i位于第i-1位所得的最小值。注意第i位如果交换,不要忘记加1哦。

  1. 初始化
    初始化也就是f[0][0]=0;显而易见,1次也没有交换当然最少交换次数为0;
    f[0][1]=1;已经交换了1次,自然最少交换次数为1;

【代码实现】

#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define N 1000
int a[N+3],b[N+3];
int f[N+3][5];
int n;
using namespace std;
int main(){
    
    
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
	f[0][0]=0;f[0][1]=1;
	for(int i=1;i<=n;i++){
    
    
		f[i][0]=f[i][1]=1e8;//求最小值,一定要初始化成一个最大值哦
		
		if(a[i-1]<a[i] && b[i-1]<b[i])//箭头1的状态转移
			f[i][0]=min(f[i][0],f[i-1][0]);
			
		if(a[i]>b[i-1] && b[i]>a[i-1])//箭头3的状态转移
		   f[i][0]=min(f[i][0],f[i-1][1]);
		   
		if(a[i] > b[i-1] && b[i] > a[i-1])//箭头2的状态转移
			f[i][1]=min(f[i][1],f[i-1][0]+1);
			
		if(a[i-1]<a[i] && b[i-1]<b[i]) //箭头4的状态转移
			f[i][1]=min(f[i][1],f[i-1][1]+1);
			
			
	}
	cout<<min(f[n][0],f[n][1]);
	return 0;
}

类似题目练习

  1. [大盗阿福]
  2. 小b与环
  3. 数组的最大代价
  4. 垃圾馅饼
  5. 更多难题…suixb372

视频讲解

荔枝微课

猜你喜欢

转载自blog.csdn.net/qq_32431299/article/details/111223582
今日推荐