标签:
Description
Input
Output
Sample Input
Sample Output
题目要求是讲10张牌合并成一堆,然后小牌放在大小+1的大牌上。
这题关键是只有10张牌,那么每张牌在自己位置上,或者在其他位置上,那么设某一位为1表示牌在自己位置上,否则为0,这样就能进行状态压缩了。
p[state],state的二进制位就是每张牌的状态。
其次就是考虑到如果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 <cstring> #include <cmath> #include <set> #include <map> #include <queue> #include <string> #include <algorithm> #define LL long long using namespace std; int a[15], p[4100], from; int Hash[15]; bool vis[4100]; int myMin(int x, int y) { if (x == -1) return y; return min(x, y); } void input() { memset(p, -1, sizeof(p)); memset(vis, false, sizeof(vis)); from = 0; for (int i = 1; i <= 10; ++i) { scanf("%d", &a[i]); Hash[a[i]] = i; from |= (1<<i); } p[from] = 0; } void spfa() { int k, v, pre; queue<int> q; q.push(from); vis[from] = true; while (!q.empty()) { k = q.front(); q.pop(); vis[k] = false; for (int i = 1; i <= 10; ++i) { if ((k & (1<<i)) && a[i] != 10) { v = a[i]+1; while (!(k&(1<<Hash[v]))) v++; pre = p[k^(1<<i)]; p[k^(1<<i)] = myMin(p[k^(1<<i)], p[k]+abs(i-Hash[v])); if (p[k^(1<<i)] != pre && !vis[k^(1<<i)]) { q.push(k^(1<<i)); vis[k^(1<<i)] = true; } } } } } void work() { spfa(); printf("%d\n", p[1<<Hash[10]]); } int main() { //freopen("test.in", "r", stdin); int T; scanf("%d", &T); for (int times = 0; times < T; ++times) { input(); work(); } return 0; }
ACM学习历程—HDU1584 蜘蛛牌(动态规划 && 状态压缩)
标签:
原文地址:http://www.cnblogs.com/andyqsmart/p/4756631.html