ACM-ICPC 2018 南京赛区网络预赛 E. AC Challenge

题解

题目大意 给你n个问题 要求每分钟解决一个问题 且不能中断 如果中断当前得分为最终得分 每个问题的得分为 解决时间*a[i] + b[i] 有的问题需要先完成某些问题才能做

使用状压DP 用二进制压缩为2^20个状态 从小到达暴力枚举每个状态 每个状态检测是否合法 是否满足转移条件 过程每次取最大

AC代码

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const int MAXN = 21;
int a[MAXN], b[MAXN], s[MAXN], n;
ll d[1 << MAXN]; //解决问题状态为i的情况下最高得分

int btcnt(int x)
{
    int cnt = 0;
    while (x)
    {
        if (x & 1)
            cnt++;
        x >>= 1;
    }
    return cnt;
}
int main()
{
#ifdef LOCAL
    freopen("C:/input.txt", "r", stdin);
#endif
    cin >> n;
    for (int i = 0; i < n; ++i) //将节点改为0~n-1 减少状态范围
    {
        int t;
        scanf("%d%d%d", &a[i], &b[i], &t);
        for (int j = 0; j < t; ++j)
        {
            int p;
            scanf("%d", &p);
            s[i] |= 1 << p - 1;
        }
    }
    memset(d, -1, sizeof(d));
    d[0] = 0; //一项都没有为0
    ll ans = 0, mx = (1 << n) - 1; //mx状态最大值
    for (int i = 1; i <= mx; ++i) //枚举全部状态
    {
        for (int j = 0; j < n; ++j) //当前项
            if ((i & 1 << j) && ~d[i & ~(1 << j)] && (i & s[j]) == s[j]) //包含当前项 不包含当前项的状态已经处理 包含当前项所有前置
            {
                d[i] = max(d[i], d[i & ~(1 << j)] + btcnt(i) * a[j] + b[j]);
                ans = max(ans, d[i]);
            }
    }
    cout << ans << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/CaprYang/article/details/82683187