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; }