zoukankan      html  css  js  c++  java
  • B监狱 noip 模拟 7.29(区间DP)

    监狱
    题目描述
        有一座监狱,有N个牢房,N个牢房呈一字排成一排的。也就是说,第i个牢房紧挨着第i+1个(除了末尾那个)。每个牢房里都关押着一名罪犯,总共N名罪犯。
        上级要求将某些罪犯释放,给了一份名单,要求每天释放一个人。
        位于相邻牢房的罪犯,他们互相之间可以谈话也可以传话,这就使得这里的N名罪犯都可以相互聊天。如果有一个人离开了,那么能和说他上话的人就会很狂躁。如果想让他们安静下来,看守必须给狂躁的人吃一顿火锅。但看守们希望送火锅的次数越少越好。请你计算需要送火锅的次数。
    123
    输入格式
    第一行两个数N和M,M表示要释放名单上的人数;
    第二行M个数,表示释放哪些人
    12
    输出格式
    仅一行,表示最少要给多少人次送火锅吃。
    1
    样例输入
    20 3
    3 6 14
    12
    样例输出
    35
     
     
     
    这道题我真的是想了很久QAQ
    开先打了个70 分算法
    一直纠结 O(m^3) 算法
    网上找了好久 题解也看了 很多 终于悟出了一些小细节
     方法一:
    定义 f[i][j] 表示 i 到 j 号 囚犯已经被释放
     
    注意 是被释放的囚犯 
    所以 对于 每一个小区间的状态都是 于原区间一样 
    那么i号释放的代价 为 他左右两边 的没有释放资格的囚犯数
     
    所以枚举断点 k
    K 将 i 到 j 分成 区间 [i,k-1] [k+1,j]  对于每个区间 都已经被算好了 k 就是第一个来更新 [i,j]的 才会 把 [i,j] 分成两个独立的区间
    所以代价为 a[j+1]-a[i-1]-2 (这里想了很久,其实想想也是  对于区间 [i,j] 是释放囚犯的集合 他其实包含了没有释放资格的囚犯 a[j+1]-a[i-1]-2 是 i-
    1号释放囚犯 和 j+1 号释放囚犯间的 人数)
    -2? 因为 自己不更新 
    所以我们有状态转移方程 
    f[i][j]=min(f[i][j],f[i][k-1]+f[k+1][j]+a[j+1]-a[i-1]-2);
    时间复杂度 O(M^3)
     
     
     
    某ruan姓同学思路:
    枚举k∈[i,j],k是区间[i,j]内第一个被放出去的囚犯,这个区间内本来有a[j+1]-a[i-1]-1个囚犯,放出去一个之后剩下a[j+1]-a[i-1]-2个囚犯都要吃火锅

    然后区间[i,j]被分成了[i,k-1]和[k+1,j]

    因为第k个囚犯被放出去了
    code:
    //
    #include<stdio.h>
    #include<bits/stdc++.h>
    using namespace std;
    #define maxnn 4002
    int f[maxnn][maxnn];
    int n,m;
    int a[101];
    int s[maxnn][maxnn];
    int sum[maxnn];
    int res[maxnn];
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=m;i++)
        {
            cin>>a[i];
        }
        sort(a+1,a+1+m);
        a[m+1]=n+1;
        for(int i=m;i>=1;i--)
        for(int j=i;j<=m;j++)
        {    f[i][j]=1e9;
            for(int k=i;k<=j;k++)
            f[i][j]=min(f[i][k-1]+f[k+1][j]+a[j+1]-a[i-1]-2,f[i][j]);
            
        }cout<<f[1][m];
    }

    至于为甚么 a[m+1]=n+1;因为 n节点不是一个有释放资格的囚犯

     方法2:
     
    f[i][j]表示将第i个区间到第j个区间的人全部合并的最小代价
    那么对于f[i][j],我们就可以枚举中间区间mid
    那么f[i][j]的求值表达是就是
    f[i][j]=min(f[i][j],f[i][mid]+f[mid+1]][j]+sum[j]-sum[i-1]-2){其中i<=mid<j}
    解释一下
    f[i][mid]+f[mid+1][j]表示的是之前进去的人请吃的火锅
    sum[j]-sum[i-1]-1表示的是这一整段区间的人数之和
    因为请吃火锅的这个人本身不吃,所以还要-1
    得到==>f[i][mid]+f[mid+1][j]+sum[j]-sum[i-1]-2
     
    合并区间!!  式子+代价
     
     
     
     
    刀剑映出了战士的心。而我的心,漆黑且残破
  • 相关阅读:
    weblogic 正常启动页面还是404
    oracle awr 生成
    jre 修改timezone 夏令时冬令时问题
    apache 2.4 配置loadbalance
    plsq 调试存储过程
    Windows怎么命令行修改文件权限
    Windows上面挂载NFS共享
    linux sar命令详解
    Tomcat Connector connectionTimeout含义和验证
    c++STL系列之Set
  • 原文地址:https://www.cnblogs.com/OIEREDSION/p/11279740.html
Copyright © 2011-2022 走看看