P2837 晚餐队列安排

此题可能用动规不太好做,主要是状态转移方程很难想个人认为,思维发散的大佬们忽视

我看了这位大佬的 dp 题解后才想到了方程,在此受我一膜%%%

嗯,说下思路:

先用 a [ i ] 数组存一下输入的编号;

然后用二维数组 dp [ i ][ 0/1 ] 来表示当前第 i 头奶牛的编号改成 1 或 2 所用的最少次数(0 表示改成 1,1 表示改成 2)

当然要考虑当前第 i 的奶牛的编号是 1 还是 2;

重点来了!!!

如果是 1 ,那么  dp [ i ][ 0 ] = dp [ i-1 ][ 0 ];dp [ i ][ 1 ] = min ( dp [ i-1 ][ 0 ],dp [ i-1 ][ 1 ] ) + 1;

说一下啥意思:当前第 i 头奶牛的编号为 1,那么将这头奶牛的编号改为 1(其实不用改)的最小次数就是第 i - 1 头奶牛的编号改成 1 的最小次数,因为你必须保证前面的编号都为   1;

如果将这头奶牛的编号改成 2(这时候就要改了,所以后面要 +1)的最小次数就是第 i-1 头奶牛的编号改成 1 或 2 的最小次数,因为编号是 2 不能保证前面的编号是 1 还是 2,所以要求最小值;

同理,如果是 2 那么 dp [ i ][ 0 ] = dp [ i-1 ][ 0 ] + 1;dp [ i ][ 1 ] = min ( dp [ i-1 ][ 0 ],dp [ i-1 ][ 1 ] );

此时 +1 就挪到了第一个状态转移方程里,因为 2 改成 1 次数要 +1 是吧。

终于搞完了状态转移方程,这个题可以结束了吧?

边界条件.......

想当然边界条件就是 dp [ 1 ][ 0 ] 和 dp [ 1 ][ 1 ] 了

所以我们只要来个  dp [ 1 ][ 2 - a [ 1 ] ] = 1;dp [ 1 ][ a [ 1 ] - 1 ] =0;

就能完美的解决 a [ 1 ] = 1 或 2 的赋值情况了qwq

好了,下面上 AC 代码:

#include<iostream>
#include<cstdio>
#include<math.h>
#include<cmath>
using namespace std;
int n,a[30001],dp[30001][2];           //a数组存放每头奶牛的编号,dp数组来求第i头奶牛改成1或2所用的最少次数
int main() 
{
    cin>>n;
    for(int i=1; i<=n; i++) cin>>a[i];
    dp[1][a[1]-1]=0;                   //完美得处理了a[1]=1或2的不同情况
    dp[1][2-a[1]]=1;
    for(int i=2; i<=n; i++) 
    {                                  //从2开始,因为1我们已经处理了
        if(a[i]==1) 
        {                              //分类讨论
            dp[i][0]=dp[i-1][0];       //重点的转移方程,没看懂请看上面详细解析
            dp[i][1]=min(dp[i-1][0],dp[i-1][1])+1;
        }
        if(a[i]==2) 
        {
            dp[i][0]=dp[i-1][0]+1;     //与a[i]==1类似
            dp[i][1]=min(dp[i-1][0],dp[i-1][1]);
        }
    }
    cout<<min(dp[n][0],dp[n][1]);      //输出最小值
    return 0;
}

完结撒花 φ(≧ω≦*)♪

posted @ 2019-03-26 10:50  暗い之殇  阅读(163)  评论(0编辑  收藏  举报