题目描述
XCX最近迷上了玩蜘蛛牌。蜘蛛牌是windowsxp操作系统自带的一款纸牌游戏,游戏规则是这样的:只能将牌拖到比它大一的牌上面(A最小,K最大),如果拖动的牌上有按顺序排好的牌时,那么这些牌也跟着一起移动,游戏的目的是将所有的牌按同一花色从小到大排好。为了简单起见,我们的游戏只有同一花色的牌,但是这样XCX又觉得太简单了,于是他把牌数增加到了n(1<=n<=100),牌随机的在一行上展开,编号从1到n,把第i号上的牌移到第j号牌上,移动距离为abs(i-j),现在你要做的是求出完成游戏的最小移动距离。
输入描述
第一行T(1<=T<=1010)代表T组数据。每组数据包括两行,第一行是一个数字n,代表有n张牌,第二行有n个数字:为1…n的一种排列。
输出描述
最小移动距离
样例输入
1 10 3 10 4 2 5 9 1 8 6 7
样例输出
16
采用区间动态规划的方式,但是直接进行区间DP是没有任何意义的,因此需要对数列进行变化一下,我们进行dp的区间[a,b]定义为高度为a到高度为b的纸牌叠加到一起,所需要的最少距离和。在一开始,我们定义数组arr[x]中存储的是高度为x的纸牌所在的位置。那么状态转移就可以写成:dp[a][b] = dp[a][j] + dp[j+1][b] + abs(arr[b]-arr[j])
代码:
#include<bits/stdc++.h>
using namespace std;
int a[105],n;
int dp[105][105];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
a[x]=i;
}
for(int k=2;k<=n;k++)
{
for(int i=1;i<=n-k+1;i++)
{
int l=i,r=i+k-1;
dp[l][r]=1e9+7;
for(int j=l;j<=r-1;j++)
dp[l][r]=min(dp[l][r],dp[l][j]+dp[j+1][r]+abs(a[r]-a[j]));
}
}
printf("%d\n",dp[1][n]);
}
return 0;
}