P1059 过河

本文介绍了一种使用状态压缩技巧的状态动态规划方法,针对特定问题场景(如青蛙跳石头)进行了优化,通过分析不同参数组合下最优解的特点,大幅减少了计算复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

状态压缩的dp



状态转移方程

f(n)=min{f(n),f(n-i)}+(n位置有石头?1:0)  S<=i<=T


对于30%的数据,L <= 10000; 
对于全部的数据,L <= 10^9。

数据规模大,需要进行压缩




第一种情况:      

      当s=t时,很简单,青蛙踩到的石头肯定是s的倍数,那么只要统计一下所有石子中有多少是s的倍数,输出即可。

第二种情况:s<t

我们先来看一组数据。s=4t=5


从数据中我们看到,12以后的点全部都是可以到达的了。如果s=4,t=5,在一段100000的距离中没有石头,其实12以后的点都是不用递推就知道肯定能到达的。那么我们用原始的方法做就会浪费很大的资源。

        所以当s=4,t=5时,如果一段没有石头的区间长度在4*5=20以外,那么我们只要递推前20就可以了,因为20后面的情况是一样的(仔细想想为什么?)。

假设s=3,t=5,那么11=3+4+4就也可以到达了。所以,只有当t=s+1时,连续的点的起始位置才能尽量后面。最坏情况就是s=9,t=10了(仔细想想为什么?)。

       跟前面的s=4,t=5的情况一样,其实s=9,t=10时只要一段没有石头的区间长度在90之外,我们都把它当做90对待就可以了。

        因此,我们每次对于一段没有石头的区间长度为x,如果x<=t(t-1),我们仍然把它当做x来处理;相反,当x>t(t-1)时,我们就把它当做t(t-1)处理。这样,最大的复杂度就是t(t-1)*(石头个数+1)=90*101=9090,比之前的复杂度大大降低。


import java.util.Arrays;
import java.util.Scanner;

public class Main
{
	public static void main(String[] args)
	{
		goriver g=new goriver();
		
	}
}


class goriver
{
	private int L;
	private int s,t,m;
	private int[] stone;
	private int[] dp;
	public goriver()
	{	
		Scanner cin=new Scanner(System.in);
		L=cin.nextInt();
		s=cin.nextInt();
		t=cin.nextInt();
		m=cin.nextInt();
		stone=new int[m+2];
		for(int i=1;i<=m;i++)
			stone[i]=cin.nextInt();
		stone[m+1]=L;
		Arrays.sort(stone);
		
		if(s==t)
		{
			int sum=0;
			for(int i=1;i<=m;i++)
				if(stone[i]%s==0)
					sum++;
			System.out.println(sum);
			return ;
		}
		
		for(int i=1;i<=m+1;i++)
			if(stone[i]-stone[i-1]>100)
			{
				int b=stone[i]-stone[i-1]-100;
				for(int j=i;j<=m+1;j++)
					stone[j]-=b;
			}
		L=stone[m+1];
		int[] dp=new int[30000];
		int[] isstone=new int[30000];
		for(int i=1;i<=m;i++)
			isstone[stone[i]]=1;
		
		Arrays.fill(dp, 1, dp.length-1, Integer.MAX_VALUE>>1);
		
		for(int i=1;i<=L;i++)
			for(int j=i-t;j<=i-s;j++)
				if(j>=0)
					dp[i]=Math.min(dp[i], dp[j]+isstone[i]);
		
		System.out.println(dp[L]);
	}
	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值