[luogu4265][USACO18FEB]Snow Boots silver

题目大意

求出最少需要丢去多少双靴子才能到达终点。

解法

解法一:

看到数据的范围,非常清楚\(O(n^3)\)能过掉所有的数据,那么我们就果断暴力。


解法二:

比较容易会想到用DP做,我一开始定义\(f[i][j]\)表示前\(i\)个格子,现在穿了第\(j\)双时的最小丢弃数。

那么决策就是每次枚举前面的第\(k\)个格子,和现在穿了第\(p\)双时的最小丢弃数,计算两者之间的距离,在转移。

但是这样无法判断是否要丢弃出最上面的那一双,这样写感觉非常的麻烦。

所以就换了一种状态:\(f[i][j]\)表示前\(i\)个格子用\(j\)双靴子能否走到。

那么我们的边界就是\(f[1][1]=1\)

而转移就非常的简单了:如果当前的状态是true,也就是能用\(j\)双到达\(i\),那么就枚举下一双\(k\),如果满足所有题目中的约束条件,那么就转移。

这样的复杂度看似是\(O(n^4)\),但是呢?我们中间有很多不会访问到的状态,一双鞋子能够更新的答案的个数是很少的。


解法三:

看到有大佬用了一维就做了出了答案,非常的好奇,看了一下,但是觉得这样思路是一样的,就是压缩了一维状态。我谈一下我的理解:\(f[i]\)表示前\(i\)个格子能否被达到,那么我们就用\(j\)来更新这个\(f\)数组,如果能够达到,而且满足题目中的约束条件,那么就说明就可以用第\(j\)双靴子来更新后面的答案,那么我们第一次更新到终点的答案就是我们的要求求解的答案。


ac代码

# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# define LL (long long)
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf (0x7f7f7f7f)
# define pb push_back
# define fi first
# define se second
# define pii pair<int,int>
using namespace std;
inline int gi(){
    int w=0,x=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
# define N (255)
int n,b;
int dep[N],d[N],s[N];
bool f[N][N];
int main(){
    n=gi(),b=gi();
    for (int i=1;i<=n;i++) dep[i]=gi();
    for (int i=1;i<=b;i++) s[i]=gi(),d[i]=gi();
    ms(f,0); f[1][1]=1;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=b;j++)
            if (f[i][j])
                for (int k=j;k<=b;k++)
                    if (dep[i]<=s[k])
                        for (int q=i+1;q<=min(n,i+d[k]);q++) 
                            if (s[k]>=dep[q]) f[q][k]=1;
    for(int i=1;i<=b;i++)
        if (f[n][i]){
            printf("%d\n",i-1);
            return 0;
        }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/chhokmah/p/10462982.html
今日推荐