zoukankan      html  css  js  c++  java
  • 洛谷 P1220 关路灯

    先附上我最开始的想法 记忆化搜索

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    int n,m,i,ans;
    int sum1[55],sum2[55],s[55],p[55];
    int jiyi[55][55][2];
    int dp(int a,int b,int z){
        int fanhui=jiyi[a][b][z];
        if(fanhui!=0){
            return fanhui;
        }else{
            if(a==1&&b==n){
                fanhui=0;
            }
            else{
                if(a==1){
                    if(z==0){
                        fanhui=dp(a,b+1,1)+sum2[b+1]*(s[b+1]-s[a]);
                    }
                    else{
                        fanhui=dp(a,b+1,1)+sum2[b+1]*(s[b+1]-s[b]);
                    }
                }
                else{
                    if(b==n){
                        if(z==0){
                            fanhui=dp(a-1,b,0)+sum1[a-1]*(s[a]-s[a-1]);
                        }else{
                            fanhui=dp(a-1,b,0)+sum1[a-1]*(s[b]-s[a-1]);
                        }
                    }
                    else{
                        if(z==0){
                            fanhui=dp(a-1,b,0)+(sum1[a-1]+sum2[b+1])*(s[a]-s[a-1]);
                            fanhui=min(fanhui,dp(a,b+1,1)+(sum1[a-1]+sum2[b+1])*(s[b+1]-s[a]));
                        }
                        else{
                            fanhui=dp(a-1,b,0)+(sum1[a-1]+sum2[b+1])*(s[b]-s[a-1]);
                            fanhui=min(fanhui,dp(a,b+1,1)+(sum1[a-1]+sum2[b+1])*(s[b+1]-s[b]));
                        }
                    }
                 }
            }
        }
        return fanhui;
    }
    int main(){
        cin>>n>>m;
        for(i=1;i<=n;i++){
            cin>>s[i];
            cin>>p[i];
        }
        sum1[0]=0;
        sum1[n+1]=0;
        for(i=1;i<=n;i++){
            sum1[i]=sum1[i-1]+p[i];
        }
        for(i=n;i>=1;i--){
            sum2[i]=sum2[i+1]+p[i];
        }
        ans=dp(m,m,0);
        cout<<ans;
        return 0;
    }

    这个程序本身是可以运行的 但是时间复杂度不允许,在洛谷数据中TLE了5个点

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    int n,m,v[55],ans=0x7fffffff;
    struct sty{
        int x,w;
        }a[55];
      //当前位置,已经关了的点,当前时间,当前总耗电,当前没关的灯的总功率。
    int min(int a,int b){
        if(a>b) return b;
        return a;
    }
    void dfs(int now,int num,int t,int sum,int su)
    {
        if(sum+su*t>=ans) return;
        if(num==n-1)
        {
        ans=min(ans,sum);
        return;
        }
        for(int i=1;i<=n;++i){
            if(now+i<=n&&!v[now+i]){
                int t1=fabs(a[now].x-a[now+i].x);
                v[now+i]=1;
                dfs(now+i,num+1,t+t1,sum+a[now+i].w*(t+t1),su-a[now+i].w);
                v[now+i]=0;
                break;
            }
        }
        for(int i=-1;i>=-n;--i)
            if(now+i>=1&&!v[now+i]){
                int t2=fabs(a[now].x-a[now+i].x);
                v[now+i]=1;
                dfs(now+i,num+1,t+t2,sum+a[now+i].w*(t+t2),su-a[now+i].w);
                v[now+i]=0;
                break;
            }
    }
    
    int main()
    {
        int su=0;
        cin>>n>>m;
        for(int i=1;i<=n;++i){
            scanf("%d%d",&a[i].x,&a[i].w);
            if(i!=m) su+=a[i].w;///统计除了出生点以外的所有点的总功率
        }
        v[m]=1;
        dfs(m,0,0,0,su);
        cout<<ans<<endl;
        return 0;
    }

    这一套是经过剪枝后的记忆化搜索,

    第一次加的判定是if(sum>ans)return ;这个很好理解,就是当前耗电大于答案,剪掉。

    第二次是if(sum+(当前已用的时间)*(当前没关的灯的总功率)>ans)return ;

    但仍然考试中TLE五个点= =


    然而这题的正统方法是区间DP

    先附上AC代码:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int MAXM=60;
    int a[MAXM],b[MAXM],sum[MAXM],n,m,c;
    int f[MAXM][MAXM][2];
    int min(int a,int b
    {return a<b?a:b;}
    int max(int a,int b)
    {return a>b?a:b;}
    int main()
    {
      scanf("%d%d",&n,&c);
      memset(f,127,sizeof(f));//赋成极大值防止后面的min出问题
      for(int i=1;i<=n;i++)
        scanf("%d%d",&a[i],&b[i]),sum[i]=sum[i-1]+b[i];
      f[c][c][0]=f[c][c][1]=0;//瞬间被关(初始化)
      for(int l=2;l<=n;l++)
        for(int i=1;i+l-1<=n;i++)
          {
        int j=i+l-1;
        f[i][j][0]=min(f[i+1][j][0]+(a[i+1]-a[i])*(sum[i]+sum[n]-sum[j]),//继续走下去是否更快
                   f[i+1][j][1]+(a[j]-a[i])*(sum[i]+sum[n]-sum[j]));//从j点折返回来是否更快(此时假设[i+1][j]被关,i亮,从j端点往回赶去关i)
    //要注意的一点是sum[n]-(sum[j]-sum[i])是包括了i这一点的电能的,因为走过来的过程中灯i也会耗电
        f[i][j][1]=min(f[i][j-1][0]+(a[j]-a[i])*(sum[i-1]+sum[n]-sum[j-1]),//同上
                   f[i][j-1][1]+(a[j]-a[j-1])*(sum[i-1]+sum[n]-sum[j-1]));
            }
      int ans=min(f[1][n][0],f[1][n][1]);
      printf("%d",ans);
      return 0;
    }

    其中f【i】【j】【0/1】是指当前关闭i-j的灯并且站在了i(三维数是0)或j(三维数是1)

    因为数据范围很和谐,所以三维轻松AC

    自定义min max是因为害怕会因为这一点点的时间而TLE

  • 相关阅读:
    深入分析Spring之IOC之加载BeanDefinition案例详解
    JDK10的新特性:var和匿名类如何运用?正确的案例讲解
    SpringMVC中如何获取请求参数?案例详解
    如何用Spring Boot集成Ehcache缓存,教你三招搞定
    基础练习-4.数列特征
    基础练习-3.字母图形
    基础练习-2. 01字串
    基础练习-1.闰年判断
    入门训练-4. Fibonacci数列
    入门训练-3.圆的面积
  • 原文地址:https://www.cnblogs.com/SKTskyking/p/12774624.html
Copyright © 2011-2022 走看看