zoukankan      html  css  js  c++  java
  • 到达型01背包---P1877 [HAOI2012]音量调节

    P1877 [HAOI2012]音量调节

    题解

    solution 1 普通dfs  60pt

    dfs 暴搜,pos 记录当前到了第几首歌,level 记录当前的音量

    一个小剪枝

    由于每换一首歌都要调节音量,也就是要么 + 下一首音量,要么 - 下一首歌音量。那么当我们发现无论是上调音量还是下降音量都不能满足 [ 0,maxlevel ] 的音量区间,那么直接 return 掉就好了,也就是我们只转移合法的音量

    ans 记录答案,可以初始化 -1 ,不合法的答案输出 -1 

    但是普通dfs会TLE

    60 pt code

    //60 pt dfs
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<string>
    #include<cstring>
    #include<queue>
    
    using namespace std;
    
    typedef long long ll;
    
    inline int read()
    {
        int ans=0;
        char last=' ',ch=getchar();
        while(ch<'0'||ch>'9') last=ch,ch=getchar();
        while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
        if(last=='-') ans=-ans;
        return ans;
    }
    
    int n,star,maxl;
    int a[105];
    int ans=-1;
    
    void dfs(int pos,int level)
    {
        if(pos>n){ans=max(ans,level);return;} 
        if(level+a[pos]>maxl&&level-a[pos]<0) return;
        if(level+a[pos]<=maxl&&level+a[pos]>=0) dfs(pos+1,level+a[pos]);
        if(level-a[pos]<=maxl&&level-a[pos]>=0) dfs(pos+1,level-a[pos]);
    }
    
    int main()
    {
        n=read();star=read();maxl=read();
        for(int i=1;i<=n;i++) a[i]=read();
        dfs(1,star);
        printf("%d
    ",ans);
        
        return 0;
    }

    solution 2 记忆化搜索 100pt

    f [ i ][ j ] 也就是 f [ pos ][ level ] 前 i 首歌音量不超过 j 的最大音量

    初始化 -1 

    记忆化避免了重复搜索,开数组的目的其实是记录下当前状态在之前有没有被搜到过,如果搜到过直接返回它

    (其实后面改DP的时候发现 f 数组里面可以没有实际内容,只是记录下有没有搜到过罢了)

    100 pt code

    //100 pt ji yi hua dfs
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<string>
    #include<cstring>
    #include<queue>
    
    using namespace std;
    
    typedef long long ll;
    
    inline int read()
    {
        int ans=0;
        char last=' ',ch=getchar();
        while(ch<'0'||ch>'9') last=ch,ch=getchar();
        while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
        if(last=='-') ans=-ans;
        return ans;
    }
    
    int n,star,maxl;
    int a[105];
    int f[55][1010];
    int ans=-1;
    
    int  dfs(int pos,int level)
    {
        if(pos>n) return ans=max(ans,level);  
        if(f[pos][level]!=-1) return f[pos][level];
        if(level+a[pos]>maxl&&level-a[pos]<0) return -1;
        if(level+a[pos]<=maxl&&level+a[pos]>=0) 
            f[pos][level]=max(f[pos][level],dfs(pos+1,level+a[pos]));
        if(level-a[pos]<=maxl&&level-a[pos]>=0) 
            f[pos][level]=max(f[pos][level],dfs(pos+1,level-a[pos]));
        return f[pos][level];
    }
    
    int main()
    {
        n=read();star=read();maxl=read();
        for(int i=1;i<=n;i++) a[i]=read();
        memset(f,-1,sizeof(f));
        dfs(1,star);
        printf("%d
    ",ans);
        
        return 0;
    }

    solution 3 到达型 01 背包

    (一开始试图直接敲正解,但是只想到了01背包而不是到达型。。。)

    所谓到达型, f [ i ][ j ] 表示前 i 首歌,能否到达音量 j ,bool 数组记录即可

    转移的时候就转移合法音量区间的就好

    初始化 由于给出开始音量,所以只有 f [ 0 ][ beginlevel ] = 1 

    100 pt code

    //100 pt 01 bag
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<string>
    #include<cstring>
    #include<queue>
    
    using namespace std;
    
    typedef long long ll;
    
    inline int read()
    {
        int ans=0;
        char last=' ',ch=getchar();
        while(ch<'0'||ch>'9') last=ch,ch=getchar();
        while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
        if(last=='-') ans=-ans;
        return ans;
    }
    
    int n,star,maxl;
    int a[105];
    bool f[55][1010];
    int ans=-1;
    
    int main()
    {
        n=read();star=read();maxl=read();
        for(int i=1;i<=n;i++) a[i]=read();
        f[0][star]=1;
        
        for(int i=1;i<=n;i++)
          for(int j=maxl;j>=0;j--){
              if(j-a[i]>=0&&j-a[i]<=maxl) f[i][j]|=f[i-1][j-a[i]];
              if(j+a[i]>=0&&j+a[i]<=maxl) f[i][j]|=f[i-1][j+a[i]];
          }
          
        for(int j=0;j<=maxl;j++){
            if(f[n][j]) ans=max(ans,j);
        } 
        printf("%d
    ",ans);
        
        return 0;
    }

    PS:CE的原因

    如果你不小心 CE 了,请不要使用 begin 作为变量

    完结撒花 /

  • 相关阅读:
    移动端开发-禁止横屏
    奇葩的对象创建方式(更新中)
    每日积累之8.8
    每日积累 8.6
    折半查找
    linux中的amount的解释
    Redis集群错误
    每日积累 8.6
    Redis中在程序中的应用
    每日积累 8.4
  • 原文地址:https://www.cnblogs.com/xiaoyezi-wink/p/12004639.html
Copyright © 2011-2022 走看看