uva 1379(dp)

题意:有n个人要和m个敌人打比赛,要打g场比赛,每天最多打一场,持续g+10天,然后给出n个人中每个人打敌人的胜率,且一个人打了比赛后需要休息4天,然后给出第i天要打的敌人序号,0表示不打,问最多能得多少分(胜率累加和)。
题解:dp的思路比较好想,f[i][x][j][k][l]表示在第i天,第i-1天是第x个人打的,第i-2天是第j个人打的,第i-3天是第k个人打的,第i-4天是第l个人打的情况下最大得分,先把打每个敌人胜率从大到小排序,然后每次只取前5个人(休息四天,要和之前的人比对是否是同一人)。
状态转移方程:
如果第i天要打比赛:
f[i][x][j][k][l] = max(f[i][x][j][k][l],f[i - 1][j][k][l][o] + p[g[i]][x])
不打:
f[i][0][j][k][l] = max(f[0][x][j][k][l],f[i - 1][j][k][l][o])

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 105;
struct Point {
    int v, id;
}p[N][N];
int n, m, d, g[N * 3], res;
int f[2][10][10][10][10];

bool cmp(Point a, Point b) {
    return a.v > b.v;
}

int judge(int x, int y) {
    if (x == 0 || y == 0)
        return 0;
    return p[x][y].id;
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d%d", &n, &m, &d);
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                scanf("%d", &p[i][j].v);
                p[i][j].id = j;
            }
            sort(p[i] + 1, p[i] + 1 + n, cmp);
        }
        res = 0;
        d += 10;
        for (int i = 1; i <= d; i++)
            scanf("%d", &g[i]);
        memset(f[0], 0, sizeof(f[0]));
        for (int i = 1; i <= d; i++) {
            int now = i % 2;
            int pre = 1 - now;
            memset(f[now], 0, sizeof(f[now]));
            if (g[i]) {
                for (int x = 1; x <= 5; x++) {
                    for (int j = 0; j <= 5; j++) {
                        if (i > 1 && judge(g[i], x) == judge(g[i - 1], j))
                            continue;
                        for (int k = 0; k <= 5; k++) {
                            if (i > 2 && judge(g[i], x) == judge(g[i - 2], k))
                                continue;
                            for (int l = 0; l <= 5; l++) {
                                if (i > 3 && judge(g[i], x) == judge(g[i - 3], l))
                                    continue;
                                for (int o = 0; o <= 5; o++) {
                                    if (i > 4 && judge(g[i], x) == judge(g[i - 4], o))
                                        continue;
                                    f[now][x][j][k][l] = max(f[now][x][j][k][l], f[pre][j][k][l][o] + p[g[i]][x].v);
                                    res = max(res, f[now][x][j][k][l]);
                                }
                            }
                        }
                    }
                }
            }
            else {
                for (int j = 0; j <= 5; j++)
                    for (int k = 0; k <= 5; k++)
                        for (int l = 0; l <= 5; l++)
                            for (int o = 0; o <= 5; o++) {
                                f[now][0][j][k][l] = max(f[now][0][j][k][l], f[pre][j][k][l][o]);
                                res = max(res, f[now][0][j][k][l]);
                            }
            }
        }
        printf("%.2lf\n", res * 1.0 / 100);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值