您的位置:首页 > 其它

ACM学习历程—HDU1584 蜘蛛牌(动态规划 && 状态压缩 || 区间DP)

2015-08-25 09:57 537 查看
Description

蜘蛛牌是windows xp操作系统自带的一款纸牌游戏,游戏规则是这样的:只能将牌拖到比她大一的牌上面(A最小,K最大),如果拖动的牌上有按顺序排好的牌时,那么这些牌也跟着一起移动,游戏的目的是将所有的牌按同一花色从小到大排好,为了简单起见,我们的游戏只有同一花色的10张牌,从A到10,且随机的在一行上展开,编号从1到10,把第i号上的牌移到第j号牌上,移动距离为abs(i-j),现在你要做的是求出完成游戏的最小移动距离。

Input

第一个输入数据是T,表示数据的组数。
每组数据有一行,10个输入数据,数据的范围是[1,10],分别表示A到10,我们保证每组数据都是合法的。

Output

对应每组数据输出最小移动距离。

Sample Input

1

1 2 3 4 5 6 7 8 9 10

Sample Output

9

题目要求是讲10张牌合并成一堆,然后小牌放在大小+1的大牌上。

这题关键是只有10张牌,那么每张牌在自己位置上,或者在其他位置上,那么设某一位为1表示牌在自己位置上,否则为0,这样就能进行状态压缩了。

p[state],state的二进制位就是每张牌的状态。p表示最优解

其次就是考虑到如果2不在自己位置上,3不在自己位置上,而4在自己位置上,那么234肯定在4的位置上,因为最多就是先3到4,然后2到3,或者先2到3,然后2、3一起到4(1不考虑的情况)

而且从中还能得到,某一位值为k的牌,可以放到k+1,k+2,k+3中第一个非0位置上。

这样状态更新就是

p[state^(1<<i)] = myMin(p[state^(1<<i)], p[state]+abs(i-j));(其中i是state的非0位,j是i以上第一个非0位)

myMin是自定义最小值,对第一个参数为-1的情况进行了特判,这里处理方式很多。

然后这个方程我不太会用for完成。用了spfa的思想前一个状态更新了会导致后面的状态更新。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <string>
#define LL long long

using namespace std;

const int maxN = 105;
int n, a[maxN];
int p[maxN][maxN];

void input()
{
memset(p, -1, sizeof(p));
scanf("%d", &n);
int k;
for (int i = 1; i <= n; ++i)
{
scanf("%d", &k);
a[k] = i;
p[i][i] = 0;
}
}

inline int myMin(int x, int y)
{
if (x == -1) return y;
else return min(x, y);
}

void work()
{
for (int j = 1; j < n; ++j)
for (int i = 1; i+j <= n; ++i)
for (int k = i; k < i+j; ++k)
p[i][i+j] = myMin(p[i][i+j], p[i][k]+p[k+1][i+j]+abs(a[k]-a[i+j]));
printf("%d\n", p[1]
);
}

int main()
{
//freopen("test.in", "r", stdin);
int T;
scanf("%d", &T);
for (int times = 1; times <= T; ++times)
{
input();
work();
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: