链接:
1654. 到家的最少跳跃次数
题意:
从0出发,到X的最少步数
- 它可以 往前 跳恰好 a个位置(即往右跳)。
- 它可以 往后 跳恰好 b个位置(即往左跳)。
- 它不能 连续 往后跳 2次。
- 它不能跳到任何 forbidden数组中的位置。
解:
乐了,这下真成傻子了
两个判断条件我把有continue的放前面了
基本的DFS+DP,要注意一下几个点
-  分成两个数组,一个装加减都可以的,一个装只能加的,vector,unordered_set都行 
-  找加减都能走的时候,条件是 dp[i+a]>=dp[i]+1而不是dp[i+a]>dp[i]+1,因为即使dp[i+a]==dp[i]+1时,有可能那一步是通过某个数减到达的,那么这个数只经过了加,而我们找加减都行就要算上他
-  对于找只能加的就很好判断了 dp[i-b]>dp[i]+1,因为这个数如果之前出现过,如果是加来的,它就经过了加减,如果是减来的,它就经过了加,总之它在这一步之前就计算过了加的结果,就不用再算了
-  上界没超过6000,这个看评论区推的,我还以为4001 
-  先算只能加的那个数组更快,原理不想想了 
-  贴个数据 
-  vector/先加/后加减 
-  vector/先加减/后加 
-  unordered_set/先加/后加减 
-  unordered_set/先加减/后加 
实际代码:
#include<bits/stdc++.h>
using namespace std;
static constexpr int Max=1E5+7;
int minimumJumps(vector<int>& forbidden, int a, int b, int x)
{
	map<int,bool>book;
	for(auto i:forbidden) book[i]=true;
	
	vector<int>dp(Max,INT_MAX-1);dp[0]=0;
	vector<int>start{0},noBack;//unordered_set 
	while(true)
	{
		vector<int>next,nextNoBack;//unordered_set
		//加 
		for(auto i:noBack)
		{
			if(book.find(i+a)!=book.end() || i+a>6001 || dp[i+a]<dp[i]+1) continue;
			else
			{
				dp[i+a]=dp[i]+1;
				next.push_back(i+a);
			}
		}
		//加减 
		for(auto i:start)
		{
			if(book.find(i-b)==book.end() && i-b>=0 && dp[i-b]>dp[i]+1)
			{
				dp[i-b]=dp[i]+1;
				nextNoBack.push_back(i-b);
			}
			if(book.find(i+a)!=book.end() || i+a>6001 || dp[i+a]<dp[i]+1) continue;
			else
			{
				dp[i+a]=dp[i]+1;
				next.push_back(i+a);
			}
		}
		start=next;
		noBack=nextNoBack;
		if(start.empty() && noBack.empty()) break;
	}
	if(x==0) return 0;
	return dp[x]==INT_MAX-1 ? -1 : dp[x];
}
int main()
{
	vector<int> forbidden;int a,b,x,temp;
	cin>>a>>b>>x;
	while(cin>>temp) forbidden.push_back(temp);
	int ans=minimumJumps(forbidden,a,b,x);
	cout<<ans<<endl;
	return 0;
}
限制:
- 1 <= forbidden.length <= 1000
- 1 <= a, b, forbidden[i] <= 2000
- 0 <= x <= 2000
- forbidden中所有位置互不相同。
- 位置 x不在forbidden中。























