HDU5259(百度之星复赛1002)——弹吉他(DP)

题目连接

题目分析

这是一道比较典型的DP题目,但是题目的状态数量比较多,转移数量也比较多,所以枚举起来会比较麻烦,所以可以用一个技巧就是可以预处理出所有的序列然后用序列枚举状态转移,这样会使代码简洁很多。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
using namespace std;

typedef long long LL;
const int MOD = 1e9 + 7;
const int INF = 10000000;
const int N = 5000 + 10;

struct State {
    int a[4], b[4]; //
    void read() {
        for(int i = 0; i < 4; i++) {
            scanf("%d%d", &a[i], &b[i]);
        }
    }
} s[N];
int seq[30][4], dp[N][30];

bool check(int b[], int q[]) { //序号大的手指所处的品位不能小于序号小的手指
    for(int i = 1; i < 4; i++) {
        if(b[q[i]] < b[q[i - 1]]) return false;
    }
    return true;
}
int calc(State& A, State& B, int q0[], int q1[]) {
    int dis = 0;
    for(int i = 0; i < 4; i++) {
        dis += abs(A.a[q0[i]] - B.a[q1[i]]);
        dis += abs(A.b[q0[i]] - B.b[q1[i]]);
    }
    return dis;
}
int main() {
#ifdef TYH
    freopen("in.txt", "r", stdin);
#endif // TYH
    int T, C = 1, n;
    int A[4] = {0, 1, 2, 3};
    int nq = 0;
    do {
        for(int i = 0; i < 4; i++) seq[nq][i] = A[i];
        nq ++;
    } while(next_permutation(A, A + 4));

    scanf("%d", &T);
    while(T--) {
        printf("Case #%d:\n", C++);
        scanf("%d" , &n);
        for(int i = 1; i <= n; i++) {
            s[i].read();
        }
        for(int i = 0; i < 4; i++)
            s[0].b[i] = i + 1, s[0].a[i] = 0;

        for(int i = 0; i < 24; i++) {
            if(check(s[1].b, seq[i])) {
                dp[1][i] = calc(s[0], s[1], seq[0], seq[i]);
            } else {
                dp[1][i] = INF;
            }
        }
        for(int i = 2; i <= n; i++) {
            for(int j = 0; j < 24; j++) {
                dp[i][j] = INF;
                if(!check(s[i].b, seq[j])) continue;
                for(int k = 0; k < 24; k++) {
                    if(dp[i - 1][k] == INF) continue;
                    dp[i][j] = min(dp[i][j], dp[i - 1][k] + calc(s[i - 1], s[i], seq[k], seq[j]));
                }
            }
        }
        int ans = INF;
        for(int i = 0; i < 24; i++) {
            ans = min(ans, dp[n][i]);
        }
        printf("%d\n", ans);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值