zoukankan      html  css  js  c++  java
  • 洛谷 P1880 石子合并 破环成链

    P1880 石子合并

    • 时空限制1s / 128MB

    题目描述

    在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

    试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.

    输入输出格式

    输入格式:

    数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.

    输出格式:

    输出共2行,第1行为最小得分,第2行为最大得分.

    输入输出样例

    输入样例#1:  
    4
    4 5 9 4
    输出样例#1: 
    43
    54
    ---------------------------------------------------------------------------------
    这道题的难点就是如何在一个环上实现DP
    环不好搞,那就把它变成一条链吧!


    其实就是就是破环成链

    做法也挺简单,就是把原来的数列扩展为原来的两倍
    然后把长度为n的数列从这个2n的数列的第一个数开始整体右移
    一共移n次,即在这个新数列上进行n次循环,找每次移动操作得出的最大或最小值
    需要注意每次移动后要清空dp状态值,因为移动后就相当于重新操作,状态值是原先转移前序列的状态值

    dp[i][j]表示合并第i个数到第j个数可获得的最大值,dpmi[i][j]则为最小值
    sum[i][j]表示第i个数到第j个数的和
    注意dpmi[i][i]==0,因为只有一个数时还没合并,所以该状态没有分数

    AC代码:
     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<iostream>
     4 #define maxn 233
     5 using namespace std;
     6 int n,dp[maxn][maxn],a[maxn],ansma,ansmi,sum[maxn][maxn],dpmi[maxn][maxn];
     7 int main(){
     8     scanf("%d",&n);
     9     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    10     
    11     for(int i=n+1;i<=n*2;i++) a[i]=a[i-n];
    12     for(int i=1;i<=maxn;i++)
    13        for(int j=1;j<=maxn;j++)
    14        dpmi[i][j]=1e9;
    15     ansmi=1e9;
    16     for(int i=1;i<=n*2;i++)
    17        for (int j=i;j<=n*2;j++) 
    18        sum[i][j]+=sum[i][j-1]+a[j];
    19        
    20     for(int i=1;i<=n;i++){
    21         
    22         for(int j=i;j<n+i-1;j++){
    23             dp[j][j+1]=sum[j][j+1];
    24             dpmi[j][j+1]=sum[j][j+1];
    25             dpmi[j][j]=0;
    26         }
    27         dpmi[n+i-1][n+i-1]=0;
    28         
    29         for(int j=2;j<=n-1;j++)
    30           for(int g=i;g+j<=n+i-1;g++)
    31               for(int k=g;k<=g+j-1;k++){
    32                  dp[g][g+j]=max(dp[g][g+j],dp[g][k]+dp[k+1][g+j]+sum[g][g+j]);
    33                  dpmi[g][g+j]=min(dpmi[g][g+j],dpmi[g][k]+dpmi[k+1][g+j]+sum[g][g+j]);
    34              }
    35         
    36         ansma=max(ansma,dp[i][n+i-1]);
    37         ansmi=min(ansmi,dpmi[i][n+i-1]);
    38         
    39         for(int i=1;i<=maxn;i++)
    40             for(int j=1;j<=maxn;j++)
    41             dpmi[i][j]=1e9;
    42         memset(dp,0,sizeof(dp));
    43         
    44     }
    45     printf("%d
    %d",ansmi,ansma);
    46     return 0;
    47 }
    破环成链

     -----------------------------------------------------------------------------------------------------------------------------

    话说上一次以以上自己想出来的做法AC后,发现以上做法跑得比其他人的慢得多,所以又回来学习了一波

    代码简化了许多,更重要的是跑得更快了

    破环成链是没错

    只是在原来dp过程中可进行很多优化

    直接放代码:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<iostream>
     4 #define maxn 233
     5 using namespace std;
     6 int read();
     7 int n,dpma[maxn][maxn],sum[maxn],a[maxn],mi,ma,dpmi[maxn][maxn];
     8 int main(){
     9     n=read();
    10     for(int i=1;i<=n;i++){
    11         a[i]=read();
    12         a[i+n]=a[i];
    13     }
    14     for(int i=1;i<=2*n;i++) sum[i]=sum[i-1]+a[i];
    15     for(int i=1;i<n;i++)//枚举区间长度 
    16        for(int j=1;j<=n*2-i;j++){//枚举起点 
    17              dpmi[j][j+i]=1e9;
    18              for(int k=j;k<j+i;k++){//枚举中点 
    19                  dpma[j][j+i]=max(dpma[j][j+i],dpma[j][k]+dpma[k+1][j+i]+sum[j+i]-sum[j-1]);
    20                  dpmi[j][j+i]=min(dpmi[j][j+i],dpmi[j][k]+dpmi[k+1][j+i]+sum[j+i]-sum[j-1]);
    21              }
    22        }
    23     mi=1e9;ma=0;
    24     for(int i=1;i<n;i++){
    25         ma=max(ma,dpma[i][i+n-1]);
    26         mi=min(mi,dpmi[i][i+n-1]);
    27     }
    28     printf("%d
    %d",mi,ma);
    29     return 0;
    30 } 
    31 int read(){
    32     int ans=0,f=1;char c=getchar();
    33     while('0'>c||c>'9'){if(c=='-')f=-1;c=getchar();}
    34     while('0'<=c&&c<='9')ans=ans*10+c-48,c=getchar();return ans*f;
    35 }
    标准做法

    然后就是从512ms到12ms的差距T_T

  • 相关阅读:
    JS基本概念 -- 操作符 -- 布尔操作符
    JS基本概念 -- 操作符 -- 一元操作符
    JS基本概念 -- 数据类型(二)
    JS基本概念 -- 数据类型(一)
    JS基本概念 -- 语法
    使用Browsersync热更新热替换,解放F5
    js中汉字utf8编码互相转换
    npm 使用代理 install 插件
    时间戳转换成yyyy-mm-dd
    Backbone.View.extend之后的构造函数实例化经历了一些什么处理
  • 原文地址:https://www.cnblogs.com/lpl-bys/p/7756510.html
Copyright © 2011-2022 走看看