题解 P3847 【[TJOI2007]调整队形】
排版已订正。
DP题。
感觉蓝题难度还是有点过了吧?
大致思路就是建一个二维数组dp【i】【j】表示从第i个人到第j个人对称的最小次数
这时候就大致可以得出动态转移方程了,如下
1.先设置一个长度l自2至n枚举
2.此时i从1枚举至n-l+1,j此时则为i+l-1。
3.当第i个人颜色等于第j个人时,dp【i】【j】则与dp【i+1】【j-1】相同,赋值;
4.如果不同的话,则为{dp【i+1】【j】,dp【i】【j-1】,dp【i+1】【j-1】}中次数最少的那一个再+1了。
故状态转移方程代码如下:
if(a[i]==a[j]) dp[i][j]=dp[i+1][j-1];//相同情况
else dp[i][j]=min(dp[i+1][j],min(dp[i][j-1],dp[i+1][j-1]))+1;
最后输出dp【1】【n】则为正解。
发现了吗?实际上代码很精简的。只要你有心,省选难度在你眼里都将是水题!
PS:初始化会WA第七个点!
#include<bits/stdc++.h>
using namespace std;
int n,a[3001],dp[3001][3001];//dp[i][j]表示i到j对称的最小次数
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int l=2;l<=n;l++)
for(int i=1;i+l<=n+1;i++)//枚举第i个人
{
int j=i+l-1;//枚举第j个人
if(a[i]==a[j]) dp[i][j]=dp[i+1][j-1];
else dp[i][j]=min(dp[i+1][j],min(dp[i][j-1],dp[i+1][j-1]))+1;
}
cout<<dp[1][n];
}
PPS:这是@M_sea dalao給我们讲解的,深入浅出Orz
PPPS:应该没有题解与这个相似吧?因为我们全机房都是听的M_sea dalao讲解的,所以可能机房会有与我相似的题解投上来QAQ