【动态规划】线性动规 状态节省

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_42725189/article/details/102489242
  • 大致规律:可以通过发现某些规律或共性来省掉某些状态以节省时空
  • 注意!! 当涉及到状态覆盖必须谨慎压维!!比如休息时间
  • 例一:LCIS
  • 题意:求最长公共上升子序列,n<3000
  • 原数组:f[i][j]:表示 a 1 . . . a i b 1 . . . b i a_1 ... a_i和b_1...b_i 的以bi结尾的最长公共上升子序列,需要i:1…n扫A串,j:1…m扫B串,k:m…1扫B串j前的最大f[i-1][k]。优化1:f[i-1][k]更新f[i][j]时只有k在变且找最大,则可以用一个数记录最大而不用扫,减掉一个循环k。优化2:发现每次只用到到f[i-1],所以可以滚动数组或重复利用,二维减到一维,节省空间
#include<bits/stdc++.h>
using namespace std;
int n,a[3005],b[3005],f[3005];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    scanf("%d",&b[i]);
    for(int val,i=1;i<=n;i++)
    {
        val=0;
        for(int j=1;j<=n;j++)
        {
            if(b[j]<a[i]&&f[j]>val)val=f[j];
            if(a[i]==b[j])
            f[j]=val+1;
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    if(f[i]>ans)
    ans=f[i];
    printf("%d",ans);
}
  • 例二:快递服务
  • 题意:给定一个完全图,三个人分别在点1.2.3,现有一些需依次到达的点,需派1人到达,问最小距离和。(位置数200,需求点1000)
  • 原数组:f[i][j][k][ii]表示第一人在i,第二人在j,第三人在k,解决了ii个需求的最小距离。但明显会时空双爆。优化一:发现一个共性,当解决了第ii个需求,那一定会有一个人在ii需求的那个点上,即可减少一个表位置的状态。优化二:每次只会用到上一次需求点的状态,可以滚动数组,减少一维空间。
  • 本题坑点:不能用floyd预处理两点最短路
#include<bits/stdc++.h>
using namespace std;
int l,n,f[205][205],q[3],dp[3][205][205];
int main()
{
	scanf("%d%d",&l,&n);
	for(int i=1;i<=l;i++)
	{
		for(int j=1;j<=l;j++)
		scanf("%d",&f[i][j]);
	}
	memset(dp[1],0x3f,sizeof(dp[1]));
	q[1]=1;
	dp[1][2][3]=0;
	int now=0;
	while(n--)
	{
		scanf("%d",&q[now]);
		memset(dp[now],0x3f,sizeof(dp[now]));
		for(int i=1;i<=l;i++)
		{
			for(int j=1;j<=l;j++)
			{
				if(i==j||j==q[now^1]||i==q[now^1])continue;
				if(dp[now^1][i][j]+f[q[now^1]][q[now]]<dp[now][i][j])
				dp[now][i][j]=dp[now^1][i][j]+f[q[now^1]][q[now]];
				if(dp[now^1][i][j]+f[i][q[now]]<dp[now][q[now^1]][j])
				dp[now][q[now^1]][j]=dp[now^1][i][j]+f[i][q[now]];
				if(dp[now^1][i][j]+f[j][q[now]]<dp[now][i][q[now^1]])
				dp[now][i][q[now^1]]=dp[now^1][i][j]+f[j][q[now]];
			}
		}
		if(n!=0)
		now^=1;
	}
	int ans=1234567890;
	for(int i=1;i<=l;i++)
	{
		for(int j=1;j<=l;j++)
		{
			if(i==j||j==q[now]||q[now]==i)continue;
			if(dp[now][i][j]<ans)
			ans=dp[now][i][j];
		}
	}
	printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_42725189/article/details/102489242