石子合并+环形石子合并+能量项链+凸多边形的划分——区间DP

news2024/12/28 12:18:58

一、石子合并 (经典例题)

设有 N 堆石子排成一排,其编号为 1,2,3,…,N。
每堆石子有一定的质量,可以用一个整数来描述,现在要将这 N 堆石子合并成为一堆。
每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同。
例如有 4 堆石子分别为 1 3 5 2, 我们可以先合并 1、2 堆,代价为 4,得到 4 5 2, 又合并 1、2 堆,代价为 9,得到 9 2 ,再合并得到 11,总代价为 4+9+11=24;
如果第二步是先合并 2、3 堆,则代价为 7,得到 4 7,最后一次合并代价为 11,总代价为 4+7+11=22。

问题是:找出一种合理的方法,使总的代价最小,输出最小代价。

输入
第一行一个数 N 表示石子的堆数 N (1 ≤ N ≤ 300)。
第二行 N 个数,表示每堆石子的质量(均不超过 1000)。

输出
输出一个整数,表示最小代价。

Input
4
1 3 5 2

Output
22
解析:
用一个状态表示一个区间,f[i][j] 表示将第 i 堆石子到第 j 堆石子合并成一堆石子的合并方式的集合。
状态转移:
例如,将 区间 [i,j] 分为 [i,k] 和 [k+1,j] ,枚举 k 在区间[i,j]的位置就能找到最小代价使得 合并这两个区间的代价最小,即 f[i][k]+f[k+1,j] 的值最小,再加上一个第 i 堆到第 j 堆的总重量即可。
因为在计算状态的时候,得保证在这个状态之前的状态已经计算完毕,所以可以采用循环区间长度从小到大的方式,进行计算。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int gcd(int a,int b) { return b? gcd(b,a%b) : a; }
typedef pair<int,int> PII;
const double PI=acos(-1.0);
const int N=310;
int n;
int s[N];
int f[N][N];
void solve()
{
    cin>>n;
    for (int i=1;i<=n;i++) cin>>s[i];
    for (int i=1;i<=n;i++) s[i] +=s[i-1];
    
    for (int len=1;len<=n;len++)
    for (int i=1;i+len-1<=n;i++)
    {
        int l=i,r=i+len-1;
        if(len!=1) f[l][r]=2e9;                             //因为当len=1时,只有一堆石子,不需要合并,代价为0
        for (int k=l;k<r;k++)
        f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+s[r]-s[l-1]);
    }
    
    cout<<f[1][n];
}
signed main()
{
    ios;
    int T=1;
    //cin>>T;
    while (T--) solve();
    return 0;
}

 

二、 环形石子合并 (加个环)

将 n 堆石子绕圆形操场排放,现要将石子有序地合并成一堆。
规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。
请编写一个程序,读入堆数 n 及每堆的石子数,并进行如下计算:
选择一种合并石子的方案,使得做 n−1 次合并得分总和最大。
选择一种合并石子的方案,使得做 n−1 次合并得分总和最小。

输入
第一行包含整数 n (1 ≤ n ≤ 200),表示共有 n 堆石子。
第二行包含 n 个整数,分别表示每堆石子的数量。

输出
共两行,第一行为合并得分总和最小值,第二行为合并得分总和最大值。

Input
4
4 5 9 4

Output
43
54

解析:
与上一题的石子合并的想法基本相似,不同的是这道题的石堆的摆放方式是环式的。
在上道题的基础上,将这个环断开,变成一条链,枚举每个断点。
不过直接枚举的话,时间复杂度是 n^4,超时了。
我们可以将数组读入,再将数组复制一遍,再接到这个数组上。
这样时间复杂度就降下来了,时间复杂度在 n^3。
注意:在做这种环式的题,就可以多想一想这样的方法

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int gcd(int a,int b) { return b? gcd(b,a%b) : a; }
typedef pair<int,int> PII;
const double PI=acos(-1.0);
const int N=410;
int n;
int a[N],s[N];
int f[N][N],g[N][N];
void solve()
{
    cin>>n;
    for (int i=1;i<=n;i++) cin>>a[i],a[i+n]=a[i];
    for (int i=1;i<=2*n;i++) s[i]=s[i-1]+a[i];
    
    for (int len=1;len<=n;len++)                //一层循环枚举区间长度
    for (int i=1;i+len-1<=2*n;i++)              //二层循环枚举区间的左右端点
    {
        int l=i,r=i+len-1;
        if (len!=1) f[l][r]=2e9,g[l][r]=-2e9;
        for (int k=l;k<r;k++)                   //状态转移
        {
            f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+s[r]-s[l-1]);
            g[l][r]=max(g[l][r],g[l][k]+g[k+1][r]+s[r]-s[l-1]);
        }
    }
    
    int minx=2e9,maxx=-2e9;                     //找到最小值,最大值
    for (int i=1;i<=n;i++) 
    {
        minx=min(minx,f[i][i+n-1]);
        maxx=max(maxx,g[i][i+n-1]);
    }
    
    cout<<minx<<endl<<maxx<<endl;
}
signed main()
{
    ios;
    int T=1;
    //cin>>T;
    while (T--) solve();
    return 0;
}

三、能量项链 (跟上个题一样)

在 Mars 星球上,每个 Mars 人都随身佩带着一串能量项链,在项链上有 N 颗能量珠。
能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数。
并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记。
因为只有这样,通过吸盘(吸盘是 Mars 人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量。

如果前一颗能量珠的头标记为 m,尾标记为 r,后一颗能量珠的头标记为 r,尾标记为 n,则聚合后释放的能量为 m×r×n(Mars 单位),新产生的珠子的头标记为 m,尾标记为 n。
需要时,Mars 人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。
显然,不同的聚合顺序得到的总能量是不同的,请你设计一个聚合顺序,使一串项链释放出的总能量最大。

例如:设 N=4,4 颗珠子的头标记与尾标记依次为 (2,3)(3,5)(5,10)(10,2)。
我们用记号 ⊕ 表示两颗珠子的聚合操作,(j⊕k) 表示第 j,k 两颗珠子聚合后所释放的能量。则
第 4、1 两颗珠子聚合后释放的能量为:(4⊕1)=10×2×3=60。
这一串项链可以得到最优值的一个聚合顺序所释放的总能量为 ((4⊕1)⊕2)⊕3)=10×2×3+10×3×5+10×5×10=710。

输入
输入的第一行是一个正整数 N (4 ≤ N ≤ 100),表示项链上珠子的个数。
第二行是 N 个用空格隔开的正整数,所有的数均不超过 1000,第 i 个数为第 i 颗珠子的头标记,当 i<N 时,第 i 颗珠子的尾标记应该等于第 i+1 颗珠子的头标记,第 N 颗珠子的尾标记应该等于第 1 颗珠子的头标记。
至于珠子的顺序,你可以这样确定:将项链放到桌面上,不要出现交叉,随意指定第一颗珠子,然后按顺时针方向确定其他珠子的顺序。

输出
输出只有一行,是一个正整数 E (1 ≤ E ≤ 2e9),为一个最优聚合顺序所释放的总能量。

Input
4
2 3 5 10

Output
710

解析:
跟上一题一样,纯套路。

//代码一:开个结构体存储头和尾,相当于一个点,就跟上道题一模一样了
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int gcd(int a,int b) { return b? gcd(b,a%b) : a; }
typedef pair<int,int> PII;
const double PI=acos(-1.0);
const int N=400;
struct node
{
    int x,y;
}str[N];
int n;
int a[N];
int f[N][N];
void solve()
{
    cin>>n;
    for (int i=1;i<=n;i++) cin>>a[i];
    for (int i=1;i<=n;i++)
    {
        if (i==1)  str[i]={a[n],a[i]};
        else str[i]={a[i-1],a[i]};
        str[i+n]=str[i];
    }
    
    for (int len=1;len<=n;len++)
    for (int i=1;i+len-1<=2*n;i++)
    {
        int l=i,r=i+len-1;
        if (len!=1) f[l][r]=-2e9;
        for (int k=l;k<r;k++)
        {
            f[l][r]=max(f[l][r],f[l][k]+f[k+1][r]+str[l].x*str[k].y*str[r].y);          //左区间左端点的头*左区间右端点的尾*右区间右端点的尾
        }
    }
    
    int ans=-2e9;
    for (int i=1;i<=n;i++) ans=max(ans,f[i][i+n-1]);
    cout<<ans;
}
signed main()
{
    ios;
    int T=1;
    //cin>>T; 
    while (T--) solve();
    return 0;
}


//代码二
//划分方式:f(l,r)=f(l,k)+f(k,r)+a[l]*a[k]*a[r]
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int gcd(int a,int b) { return b? gcd(b,a%b) : a; }
typedef pair<int,int> PII;
const double PI=acos(-1.0);
const int N=400;
int n;
int a[N];
int f[N][N];
void solve()
{
    cin>>n;
    for (int i=1;i<=n;i++) cin>>a[i],a[i+n]=a[i];
    
    for (int len=3;len<=n+1;len++)                      //至少 3 个点
    for (int i=1;i+len-1<=2*n;i++)
    {
        int l=i,r=i+len-1;
        f[l][r]=-2e9;
        for (int k=l;k<r;k++)
        {
            f[l][r]=max(f[l][r],f[l][k]+f[k][r]+a[l]*a[k]*a[r]); 
        }
    }
    
    int ans=-2e9;
    for (int i=1;i<=n;i++) ans=max(ans,f[i][i+n]);      //查找区间长度为 n+1 的
    cout<<ans;
}
signed main()
{
    ios;
    int T=1;
    //cin>>T; 
    while (T--) solve();
    return 0;
}

 四、凸多边形的划分

给定一个具有 N 个顶点的凸多边形,将顶点从 1 至 N 标号,每个顶点的权值都是一个正整数。
将这个凸多边形划分成 N−2 个互不相交的三角形,对于每个三角形,其三个顶点的权值相乘都可得到一个权值乘积,试求所有三角形的顶点权值乘积之和至少为多少。

输入
第一行包含整数 N (N ≤ 50),表示顶点数量。
第二行包含 N 个整数,依次为顶点 1 至顶点 N 的权值。

输出
输出仅一行,为所有三角形的顶点权值乘积之和的最小值。
数据保证所有顶点的权值都小于 1e9

Input
5
121 122 123 245 231

Output
12214884

 解析:


f[l][r] 表示 所有 由(l,l+1)(l+1,l+2)……(r-1,r)(r,l)这些边组成的多边形 划分成三角形的方案的集合。
跟上道题的划分是一样的,不过不需要破环成链,因为枚举哪一条边都是一样的。
这里的运算数据太大,需要高精度运算。

//代码一:没有加高精度的代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int gcd(int a,int b) { return b? gcd(b,a%b) : a; }
typedef pair<int,int> PII;
const double PI=acos(-1.0);
const int N=110;
int n;
int w[N];
int f[N][N];
int INF=1e18;
void solve()
{
    cin>>n;
    for (int i=1;i<=n;i++) cin>>w[i];
    
    for (int len=3;len<=n;len++)
    for (int i=1;i+len-1<=n;i++)
    {
        int l=i,r=i+len-1;
        f[l][r]=INF;
        for (int k=l;k<r;k++)
        {
            f[l][r]=min(f[l][r],f[l][k]+f[k][r]+w[l]*w[k]*w[r]);
        }
    }
    
    cout<<f[1][n];
}
signed main()
{
    ios;
    int T=1;
    //cin>>T; 
    while (T--) solve();
    return 0;
}



//代码二:加了高精度的代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int gcd(int a,int b) { return b? gcd(b,a%b) : a; }
typedef pair<int,int> PII;
const double PI=acos(-1.0);
const int N=55,M=35,INF=1e9;
int n;
int w[N];
int f[N][N][M];
int c[M];
void add(int a[],int b[])
{
    memset(c,0,sizeof c);
    int t=0;
    for (int i=0;i<M;i++)
    {
        t +=a[i]+b[i];
        c[i]=t%10;
        t /=10;
    }
    memcpy(a,c,sizeof c);
}
void mul(int a[],int b)
{
    memset(c,0,sizeof c);
    int t=0;
    for (int i=0;i<M;i++)
    {
        t +=a[i]*b;
        c[i]=t%10;
        t /=10;
    }
    memcpy(a,c,sizeof c);
}
int cmp(int a[],int b[])
{
    for (int i=M-1;i>=0;i--)
    {
        if (a[i]>b[i]) return 1;
        else if (a[i]<b[i]) return -1;
    }
    return 0;
}
void print(int a[])
{
    int k=M-1;
    while (k&&!a[k]) k--;
    while (k>=0) cout<<a[k--];
    cout<<endl;
}
int temp[M];
void solve()
{
    cin>>n;
    for (int i=1;i<=n;i++) cin>>w[i];
    
    for (int len=3;len<=n;len++)
    for (int i=1;i+len-1<=n;i++)
    {
        int l=i,r=i+len-1;
        f[l][r][M-1]=1;
        for (int k=l+1;k<r;k++)
        {
            memset(temp,0,sizeof temp);
            temp[0]=w[l];
            mul(temp,w[k]);
            mul(temp,w[r]);
            add(temp,f[l][k]);
            add(temp,f[k][r]);
            if (cmp(f[l][r],temp)>0) memcpy(f[l][r],temp,sizeof temp);
        }
    }
    
    print(f[1][n]);
}
signed main()
{
    ios;
    int T=1;
    //cin>>T; 
    while (T--) solve();
    return 0;
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1449605.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录算法训练营第十七天|Leetcode110 平衡二叉树、Leetcode257 二叉树的所有路径、Leetcode404 左叶子之和

代码随想录算法训练营第十七天|Leetcode110 平衡二叉树、Leetcode257 二叉树的所有路径、Leetcode404 左叶子之和 ● Leetcode110 平衡二叉树● 解题思路● 代码实现 ● Leetcode257 二叉树的所有路径● 解题思路● 代码实现 ● Leetcode404 左叶子之和● 解题思路● 代码实现 …

C++集群聊天服务器 nginx+redis安装 笔记 (中)

一、nginx安装 nginx: download 下载nginx安装包 hehedalinux:~/package$ tar -zvxf nginx-1.24.0.tar.gz nginx-1.24.0/ nginx-1.24.0/auto/ nginx-1.24.0/conf/ nginx-1.24.0/contrib/ nginx-1.24.0/src/ nginx-1.24.0/configure nginx-1.24.0/LICENSE nginx-1.24.0/README…

【并发编程】ThreadPoolExecutor类

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;并发编程⛺️稳重求进&#xff0c;晒太阳 ThreadPoolExecutor 1) 线程池状态 ThreadPoolExecutor 使用 int 的高 3 位来表示线程池状态&#xff0c;低 29 位表示线程数量 状态名 高三位 …

详解tomcat中的jmx监控

目录 1.概述 2.如何开启tomcat的JMX 3.tomcat如何实现JMX的源码分析 1.概述 本文是博主JAVA监控技术系列文章的第二篇&#xff0c;前面一篇文章中我们介绍了JAVA监控技术的基石——jmx&#xff1a; 【JMX】JAVA监控的基石-CSDN博客 本文我们将从使用和源码实现两个方面聊…

C语言习题----不同版本的差别

这个程序数组越界&#xff0c;但是结果是死循环&#xff1b; &#xff08;1&#xff09;死循环的这种情况只会在debug--x86的版本才会出现&#xff0c;其他版本不会出现&#xff1b;这种情况会在特定的情况下发生&#xff0c;和环境有和大的关系&#xff0c;不同的编译器对于内…

(三)【Jmeter】以模板创建并剖析第一个JMeter测试计划

部署好”Jmeter“。后续操作以windows操作系统为主&#xff0c;在环境变量path中增加jmeter环境变量&#xff1a; 启动Jmeter 执行命令WINR,在输入框输入”jmeter“ 后台日志如下&#xff1a; StatusConsoleListener 该监听器在以后会被废弃掉 命令行格式&#xff1a; jmet…

TCP和UDP相关问题(重点)——7.TCP的流量控制怎么实现的?

流量控制就是在双方通信时&#xff0c;发送方的速率和接收方的速率不一定是相等的&#xff0c;如果发送方发送的太快&#xff0c;接收方就只能把数据先放到接收缓冲区中&#xff0c;如果缓冲区都满了&#xff0c;那么处理不过来就只能丢弃&#xff0c;所以需要控制发送方的速率…

CCF编程能力等级认证GESP—C++2级—20231209

CCF编程能力等级认证GESP—C2级—20231209 单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09;判断题&#xff08;每题 2 分&#xff0c;共 20 分&#xff09;编程题 (每题 25 分&#xff0c;共 50 分)小杨做题小杨的 H 字矩阵 参考答案单选题判断题编程题1编程题2 …

NLP快速入门

NLP入门 课程链接&#xff1a;https://www.bilibili.com/video/BV17K4y1W7yb/?p1&vd_source3f265bbf5a1f54aab2155d9cc1250219 参考文档链接1&#xff1a;NLP知识点&#xff1a;Tokenizer分词器 - 掘金 (juejin.cn) 一、分词 分词是什么&#xff1f; 每个字母都有对应…

easyx搭建项目-永七大作战(割草游戏)

永七大作战 游戏介绍&#xff1a; 永七大作战 游戏代码链接&#xff1a;永七大作战 提取码&#xff1a;ABCD 不想水文了&#xff0c;直接献出源码&#xff0c;表示我的诚意

【测接口试】JMeter接口关联测试

‍‍1 前言 我们来学习接口管理测试&#xff0c;这就要使用到JMeter提供的JSON提取器和正则表达式提取器了&#xff0c;下面我们来看看是如何使用的吧。 2 JSON提取器 1、添加JSON提取器 在线程组右键 > 添加 > 后置处理器 > JSON提取器 2、JSON提取器参数说明 N…

代码随想录算法训练营第二十六天|332.重新安排行程,51. N皇后,37. 解数独,总结

系列文章目录 代码随想录算法训练营第一天|数组理论基础&#xff0c;704. 二分查找&#xff0c;27. 移除元素 代码随想录算法训练营第二天|977.有序数组的平方 &#xff0c;209.长度最小的子数组 &#xff0c;59.螺旋矩阵II 代码随想录算法训练营第三天|链表理论基础&#xff…

Json-序列化字符串时间格式问题

序列化字符串时间格式问题 一、项目场景二、问题描述三、解决方案 一、项目场景 最近C#中需要将实体进行json序列化&#xff0c;使用了Newtonsoft.Json public static void TestJson(){DataTable dt new DataTable();dt.Columns.Add("Age", Type.GetType("Sys…

(13)Hive调优——动态分区导致的小文件问题

前言 动态分区指的是&#xff1a;分区的字段值是基于查询结果自动推断出来的&#xff0c;核心语法就是insertselect。 具体内容指路文章&#xff1a; https://blog.csdn.net/SHWAITME/article/details/136111924?spm1001.2014.3001.5501文章浏览阅读483次&#xff0c;点赞15次…

codechef121轮(A-G)

codechef121轮&#xff08;A-G)题解 ⭐️A.Leg Space 题目&#xff1a; &#x1f31f;题解&#xff1a; 很简单&#xff0c;比较就行 代码&#xff1a; #include <bits/stdc.h> using namespace std; int main() {// your code goes here int n,m;cin>>n>>…

尚硅谷最新Node.js 学习笔记(二)

目录 五、HTTP协议 5.1、概念 5.2、请求报文的组成 5.3、HTTP 的请求行 5.4、HTTP 的请求头 5.5、HTTP 的请求体 5.6、响应报文的组成 5.7、创建HTTP服务 操作步骤 测试 注意事项 5.8、浏览器查看 HTTP 报文 查看请求行和请求头 查看请求体 查看URL查询字符串 …

【C语言】指针练习篇(上),深入理解指针---指针和数组练习题和sizeof,strlen的对比【图文讲解,详细解答】

欢迎来CILMY23的博客喔&#xff0c;本期系列为【C语言】指针练习篇&#xff08;上&#xff09;&#xff0c;深入理解指针---指针数组练习题和sizeof&#xff0c;strlen的对比【图文讲解,详细解答】&#xff0c;图文讲解指针和数组练习题&#xff0c;带大家更深刻理解指针的应用…

企业计算机服务器中了mkp勒索病毒怎么办?Mkp勒索病毒解密处理

随着网络技术的不断发展&#xff0c;企业的生产运营也加大了步伐&#xff0c;网络为企业的生产运营提供了强有力保障&#xff0c;但网络是一把双刃剑&#xff0c;给企业带来便利的同时也为企业带来了严重的数据威胁。春节期间&#xff0c;云天数据恢复中心接到很多企业的值班人…

UnityShader——04渲染流水

渲染流水 GPU应用阶段 把数据加载到显存中设置渲染状态调用DrawCall 将渲染所需数据从硬盘加载到内存中&#xff0c;网格纹理等数据又被加载到显存中&#xff08;一般加载到显存后内存中的数据就会被移除&#xff09; 这些状态定义了场景中的网格是怎样被渲染的。例如&#xf…

AI - 碰撞避免算法分析(ORCA)

对比VO/RVO ORCA算法检测碰撞的原理和VO/RVO基本一样的&#xff0c;只是碰撞区域的计算去掉了一定时间以外才可能发生的碰撞&#xff0c;因此碰撞区域的扇形去掉了前面的部分&#xff0c;由圆锥头变成了个圆 另一个最主要的区别是&#xff0c;求新的速度&#xff0c;是根据相…