zoukankan      html  css  js  c++  java
  • P1622 释放囚犯

    传送门

    区间DP简介:

      在写这题前,需要先弄清楚区间DP是如何操作的:

      区间DP的做法还是相对固定的,没有其他类型DP的复杂多变。主要思想就是先在小区间进行DP得到最优解,然后再利用小区间的最优解合并求大区间的最优解。实现起来也十分简单,即枚举区间长度,再枚举左端点,之后枚举区间的断点进行转移。(不同的题目,有不同的转移方式)。

      下面给出区间DP最简单形式的伪代码(具体要根据题目修改)

    //mst(dp,0) 初始化DP数组
    for(int i=1;i<=n;i++)
    {
        dp[i][i]=初始值
    }
    for(int len=2;len<=n;len++)  //区间长度
    for(int i=1;i<=n;i++)        //枚举起点
    {
        int j=i+len-1;           //区间终点
        if(j>n) break;           //越界结束
        for(int k=i;k<j;k++)     //枚举分割点,构造状态转移方程
        {
            dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+w[i][j]);
        }
    }

     题解:

      区间dp的套路:设 f [ i ] [ j ] 为区间释放 i ~ j 号囚犯所需最少的肉(注意, i , j 不是牢房编号,是释放的囚犯编号,也就是下面的 a [ i ] 数组)

      枚举区间的分界点 k ,转移方程为:

        f [ i ] [ j ] =min { f [ i ] [ j ] , f [ i ] [ k-1 ] + f [ k+1 ] [ j ] + a [ j+1 ] - a [ i-1 ] -1 -1 }

      把后面这一块拿出来拆开看看, f [ i ] [ k-1 ] + f [ k+1 ] [ j ] + a [ j+1 ] - a [ i-1 ] -1 -1

        f [ i ] [ k-1 ] + f [ k+1 ] [ j ],这个不必解释

      a [ j+1 ] - a [ i-1 ] -1就是第 j+1 个要放出的囚犯到第 i-1 个要放出的囚犯之间的人数,也就是要发的肉的数量;

      最后一个 -1 是什么呢,就是第k个放出去的囚犯,不用给他吃肉了

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cstdlib>
    #include<iostream>
    #include<stack>
    #include<queue>
    #include<deque>
    #include<vector>
    #include<map>
    #include<set>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define maxn 2501
    int n,m;
    int a[maxn];
    int f[maxn][maxn];
    inline int read()
    {
        char kr=0;
        char ls;
        for(;ls>'9'||ls<'0';kr=ls,ls=getchar());
        int xs=0;
        for(;ls>='0'&&ls<='9';ls=getchar())
        {
            xs=xs*10+ls-48;
        }
        if(kr=='-') xs=0-xs;
        return xs;
    }
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            a[i]=read();
        }
        sort(a+1,a+m+1);//排序,有序的才能转移状态 
        a[0]=0;a[m+1]=n+1;//假设0和n+1号牢房有人,方便后面的状态转移(我就因为没有初始化输出负数) 
        for(int l=1;l<=m;l++)//枚举区间长度
            for(int i=1;i+l-1<=m;i++)//区间左端点位置
            {
                int j=i+l-1;//区间右端点位置
                f[i][j]=INF;
                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]-1-1);
                    //状态转移 
            }
        printf("%d
    ",f[1][m]);//输出 
    return 0;
    }
  • 相关阅读:
    crm-ssh-列表显示(顾客列表,用户,联系人列表)
    leetcode- Rotate Array 旋转数组
    ssh的整合
    svn详解和使用
    leetcode-Plus One 加一
    spring-jdbc-aop事务
    leetcode-Remove Duplicates from Sorted Array
    0020 DRF框架开发(07 基类视图 GenericAPIView)
    0019 DRF框架开发(06 基类视图 APIView)
    0018 DRF框架开发(05 序列化器的字段与选项)
  • 原文地址:https://www.cnblogs.com/lck-lck/p/9664235.html
Copyright © 2011-2022 走看看