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
     
    合并区间!!  式子+代价
     
     
     
     
    刀剑映出了战士的心。而我的心,漆黑且残破
  • 相关阅读:
    FZU 2150 Fire Game
    POJ 3414 Pots
    POJ 3087 Shuffle'm Up
    POJ 3126 Prime Path
    POJ 1426 Find The Multiple
    POJ 3278 Catch That Cow
    字符数组
    HDU 1238 Substing
    欧几里德和扩展欧几里德详解 以及例题CodeForces 7C
    Codeforces 591B Rebranding
  • 原文地址:https://www.cnblogs.com/OIEREDSION/p/11279740.html
Copyright © 2011-2022 走看看