此题可能用动规不太好做,主要是状态转移方程很难想个人认为,思维发散的大佬们忽视。
我看了这位大佬的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;
}