• 【洛谷P1622】释放囚犯【区间DP】


    题目描述

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

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

    输入格式

    第一行两个整数 P P P Q Q Q Q Q Q 表示释放名单上的人数;
    第二行 Q Q Q 个整数,表示要释放哪些人。

    输出格式

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

    样例输入 #1

    20 3
    3 6 14
    
    • 1
    • 2

    样例输出 #1

    35
    
    • 1

    样例说明 #1

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

    数据规模与约定

    • 对于 50 % 50\% 50% 的数据, 1 ≤ P ≤ 100 1 \le P \le 100 1P100 1 ≤ Q ≤ 5 1 \le Q \le 5 1Q5
    • 对于 100 % 100\% 100% 的数据, 1 ≤ P ≤ 1 0 3 1 \le P \le 10^3 1P103 1 ≤ Q ≤ 100 1 \le Q \le 100 1Q100 Q ≤ P Q \le P QP

    分析

    这道题看似是将区间“割裂”,但是反过来,我们用合并区间的思想做。

    区间DP循环模板:长度 l e n len len+起点 i i i +分割点 k k k

    f [ i ] [ j ] f[i][j] f[i][j]为合并区间 [ a [ i ] , a [ j ] ] [a[i],a[j]] [a[i],a[j]] 的最小代价。

    我们把 a [ 0 ] a[0] a[0] 设为0,最后一个设为n+1。

    当你选中一段连续区间中的一个人要放掉的时候,先用递归的思想考虑如何计算。对于最大的一个区间先分割一次,出现两个小区间,再分割直到有 m − 1 m-1 m1 个区间,再统计单位区间的答案。但是递归实际上是递推,所以直接从小区间的值算起,然后合并成大区间,合并的代价与分割时计算的代价是一样的。
    统计答案那当然是枚举这个区间内放谁,统计这个人在这个区间内影响的人,其实就是“扩展”到整个区间有多少要吃肉的,这个用 a a a 数组减就可以了,然后要再减去自己本身和一个区间头的人

    状态转移方程: f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ i ] [ k − 1 ] + f [ k + 1 ] [ j ] + a [ j + 1 ] − a [ i − 1 ] − 2 ) ; f[i][j]=min(f[i][j],f[i][k-1]+f[k+1][j]+a[j+1]-a[i-1]-2); f[i][j]=min(f[i][j],f[i][k1]+f[k+1][j]+a[j+1]a[i1]2);

    上代码

    #include
    #include
    #include
    using namespace std;
    
    int n,m,a[110],f[1010][1010],last;
    
    int main()
    {
    	cin>>n>>m;
    	for(int i=1;i<=m;i++) scanf("%d",&a[i]);
    	a[0]=0,a[m+1]=n+1; 
    	for(int len=1;len<=m;len++)
    	{
    		for(int i=1;i<=m-len+1;i++)
    		{
    			int j=i+len-1;
    			f[i][j]=0x3f3f3f3f;//只能对于这个初始化,其他都是0,不然没法更新 
    			for(int k=i;k<=j;k++)
    			{
    				f[i][j]=min(f[i][j],f[i][k-1]+f[k+1][j]+a[j+1]-a[i-1]-2);
    				/*跳过k点,统计区间答案,递归思想的话就是变成子问题,但是这个地方
    				是由小区间合并成大区间,-2是因为有个是本身,有个不存在*/ 
    			}
    		}
    	}
    	cout<<f[1][m];
    	return 0;
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
  • 相关阅读:
    R统计绘图-变量分组相关性网络图(igraph)
    java计算机毕业设计基于ssm的大学生心理健康网站
    springboot定时任务
    讲讲springboot的@Async
    测试开发基础 | Python 算法与数据结构面试题系列一(附答案)
    短视频平台爆火的AI配音|超实用的配音工具分享篇
    什么是广电入库
    Python作业【简单算法题】
    notepad++ 批量替换删除指定字符之后 或者 之前的字符,Notepad+批量替换使用大全
    Web配置过滤器,Cookie对象的简单使用
  • 原文地址:https://blog.csdn.net/dglyr/article/details/126361420