P2837 晚餐队列安排

P2837 晚餐队列安排

我们先来理解一下题意:

   奶牛保持一个混乱的顺序站好不动,手里拿着的牌只有可能是1号或 2 号,农场主很懒 要改它们的牌改成以下三种:

     111111111(全是第一批)

     22222222(全是第二批)

     111112222(前边是第一批,后边是第二批)

     注意不可以是22222111111,因为1,2代表了吃饭的批次,第一批,第二批  

     本蒟蒻一开始曲解题意以为相同数字排在一起就好了

 

SO

我们设 f [ i ] [ 1 ] 为奶牛 i 号要把自己改成 1 时农场主需要改的最少号码数

            f [ i ] [ 2 ] 为奶牛 i 号要把自己改成 2 时农场主需要改的最少号码数

            (已经改到了第 i 头奶牛)

如果此时奶牛 i 是1,那么它分两种情况讨论:

          (1)把自己改成1 它本来就是 

                   所以它就不用改了,此时农场主需要改的号码数就由 i -1奶牛决定

                   i 奶牛已经是1了,所以为了前方保持一致,倒推 i - 1奶牛也是 1

                   转移方程为:f [ i ] [ 1 ] = f [ i - 1 ] [ 1 ] ; 

 

          (2)把自己改成2

                   农场主一定要改它,所以一定要+1

                   那么第  i - 1 只奶牛可能改为 1 或 2 ,所以要取最小值

                   转移方程为:f [ i ] [ 2 ] = min ( f [ i - 1 ] [ 2 ] , f [ i - 1 ] [ 1 ] ) + 1 ;

如果此时奶牛 i 是2,依次类推;

 

那么

最后比较 f [ n ] [ 1 ] , f [ n ] [ 2 ] ,即把最后一只牛改成1 还是2 所需改的次数最少即可

 

 

 

DP代码

#include<iostream>
#include<cstdio>
#include<cmath> 
#include<algorithm>
using namespace std;
int n,a[30001],f[30001][3],ans;
int main()
{    
    scanf("%d",&n);
    
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);

    for(int i=1;i<=n;i++)
    {
        if(a[i]==1)
        {
            f[i][1]=f[i-1][1];
            f[i][2]=min(f[i-1][2],f[i-1][1])+1;
        }
        else
        {
            f[i][1]=f[i-1][1]+1;
            f[i][2]=min(f[i-1][2],f[i-1][1]);
        }
    }
    
    ans=min(f[n][1],f[n][2]);

    printf("%d",ans);
  
    return 0;
}

 

posted @ 2019-03-27 11:23  晔子  阅读(275)  评论(0编辑  收藏  举报