zoukankan      html  css  js  c++  java
  • [p1880][NOI1995]石子合并

    题目描述

    在一个圆形操场的四周摆放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


    dalaoの题解:(wsqtql%%%)

    大概思路:

    这题看起来不太好下手的亚子(dp蒟蒻的苦恼)

    看了不少题解总结出的思路:先把所有石子复制一遍,模拟出环,再进行区间DP。而在DP时,直接枚举刀口的位置,区间的起点和长度会浪费很多时间,因为刀口不一定正好落在区间内。所以先枚举长度和起点,再根据已知的区间去枚举刀口的位置可以有效地解决这个问题。

    (这题算是个区间DP的板子题,代码就放在这里)

    代码:

    #include<iostream>
    #include<cstdio> 
    #include<cmath>
    #include<cstring>
    using namespace std;
    int Fmin[201][201];
    int Fmax[201][201];
    int sum[1001];
    int num[1001];
    int n;
    void read(int &x)
    {
        char c=0;
        x=0;
        while(!isdigit(c))
        c=getchar();
        while(isdigit(c))
        x=x*10+c-'0',c=getchar();
    }//快读(只适用于正数) 
    int main()
    {
        memset(Fmin,0x3f3f3f,sizeof(Fmin));
        read(n);
        for(int i=1;i<=n;i++)
        {
            read(num[i]); 
            num[i+n]=num[i];//前缀和可以快速处理出合并时所需的代价 
            Fmin[i][i]=0;
        }
        for(int i=1;i<=2*n;i++)
        {
            sum[i]=sum[i-1]+num[i];
            Fmin[i+n][i+n]=0;
        } 
        for(int p=1;p<=n;p++)//枚举区间长度 
        {
        for(int i=1;i+p<=2*n;i++)//区间起点 
        {   
            int pos=i+p-1;//终点在这 
            for(int k=i;k<pos;k++)//枚举刀口 
            {
                Fmin[i][pos]=min(Fmin[i][pos],Fmin[i][k]+Fmin[k+1][pos]+sum[pos]-sum[i-1]);
                Fmax[i][pos]=max(Fmax[i][pos],Fmax[i][k]+Fmax[k+1][pos]+sum[pos]-sum[i-1]);
                
            }
        }
        } 
         int Max=-1;
         int Min=0x3f3f3f;
         for(int i=1;i<=2*n;i++)
         {
             Max=max(Max,Fmax[i][i+n-1]);//由于是环状,i+n-1正好是一种合并的方法 
             Min=min(Min,Fmin[i][i+n-1]);
         
         }
         cout<<Min<<endl<<Max;
        return 0;
    }

    再看道题吧。。

    题目描述

    Caima王国中有一个奇怪的监狱,这个监狱一共有P个牢房,这些牢房一字排开,第i个紧挨着第i+1个(最后一个除外)。现在正好牢房是满的。

    上级下发了一个释放名单,要求每天释放名单上的一个人。这可把看守们吓得不轻,因为看守们知道,现在牢房中的P个人,可以相互之间传话。如果某个人离开了,那么原来和这个人能说上话的人,都会很气愤,导致他们那天会一直大吼大叫,搞得看守很头疼。如果给这些要发火的人吃上肉,他们就会安静点。

    输入格式

    第一行两个数P和Q,Q表示释放名单上的人数;

    第二行Q个数,表示要释放哪些人。

    【数据规模】

    对于100%的数据1≤P≤1000; 1≤Q≤100;Q≤P;且50%的数据 1≤P≤100;1≤Q≤5

    输出格式

    仅一行,表示最少要给多少人次送肉吃。

    输入输出样例

    输入 #1
    20 3
    3 6 14
    输出 #1
    35
    
    
    

    说明/提示

    【样例说明】

    先释放14号监狱中的罪犯,要给1到13号监狱和15到20号监狱中的19人送肉吃;再释放6号监狱中的罪犯,要给1到5号监狱和7到13号监狱中的12人送肉吃;最后释放3号监狱中的罪犯,要给1到2号监狱和4到5号监狱中的4人送肉吃。

     
     

     大概思路:

    想了大概有一个小时。。怎么都想不出来要怎么写。。

    因为每一个状态都有后效性,所以正着想怎么也解不出来。。。

    后来看了一下大佬的题解,把要释放的人视作断点,将p个人分成q+1个区间,求合并区间至一个区间所需最小值,即可视为合并石子,突然通悟......不过要注意分成q+1个区间时的一些细节。。

    顿悟

    顿悟!!!!

    (代码就点这里吧)

  • 相关阅读:
    python-正则表达式
    python-定制类
    阿里云全新发布云市场能力中心,招募10个领域、500家供应商
    《DNS攻击防范科普系列3》 -如何保障 DNS 操作安全
    《DNS攻击防范科普系列2》 -DNS服务器怎么防DDoS攻击
    《DNS攻击防范科普系列1》—你的DNS服务器真的安全么?
    云栖干货回顾 |“顶级玩家”集结!分布式数据库专场精华解读
    AnalyticDB for PostgreSQL 6.0 新特性介绍
    云栖干货回顾 | 云原生数据库POLARDB专场“硬核”解析
    从零开始入门 K8s | 可观测性:你的应用健康吗?
  • 原文地址:https://www.cnblogs.com/Daz-Os0619/p/11693455.html
Copyright © 2011-2022 走看看