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的赋值情况了

好了,下面上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;
}

猜你喜欢

转载自www.cnblogs.com/xcg123/p/10598751.html