AcWing 5729. 闯关游戏 状态压缩dp

//由于这道题的数据范围是非常小的,只到18,所以考虑状压dp
//第一维一般是状态,而第二位一般是划分的重要依据
//由于只要知道最后一次通关的游戏,我们就可以计算下一步选任意一个游戏的收益,而之前选了什么游戏是完全不重要的,
//所以第二维只需要记录下最后一次选了什么游戏就可以了
//状态表示:f[i][j]表示的是状态为i且最后一次选了第j号游戏的全部方案,属性为获得分数的最大值
//状态计算:集合划分,按照倒数第二次选了什么游戏进行划分
//          f[i][j] = max(f[i][j] , f[i/j][k]) k是任意一个和j不同的游戏

#include<iostream>
#include<algorithm>

using namespace std;

const int N = 20 , M = 1<<N;
typedef long long LL; //由于最后的结果可能很大,所以开个long long

LL f[M][N];  //存的是全部状态的属性值
int w[N];  //存每个关卡的通关分数
int g[N][N];  //存全部的联动关系和分数

int main()
{
    int n,m,K;
    cin >> n >> m >> K;

    for(int i=0 ; i<n; i ++)  //读入全部的通关分数
    {
        cin >> w[i];
    }

    for(int i=0 ; i<K ; i ++) //读入全部的联动关系
    {
        int x,y,c;
        cin >> x >> y >> c;
        g[x-1][y-1] = c;
    }

    //初始化,意思是初始化所有只打一关的方案
    for(int i=0 ; i<n; i ++) f[1<<i][i] = w[i];

    //开始遍历全部的状态
    for(int i=0 ; i< 1 << n ; i ++)
    {
        for(int j=0 ; j<n; j ++)  //遍历全部的关卡
        {
            if(i >> j & 1)  //表示的是这个状态是合法的,即i这个状态是包含了j这一关卡的  (1打着一关 ,0 不打)
            {
                for(int k=0 ; k<n; k ++) //进行状态计算的过程
                {
                    if(k != j && (i >> k & 1)) //表示的i/j的状态中是包含k这个关卡的合法状态
                        f[i][j] = max(f[i][j] , f[i- (1<<j)][k] + g[k][j] + w[j]);
                }
            }
        }
    }

    //然后需要遍历全部的状态找到所有合法的满足恰好打过m关的所有状态,然后找到最后的最大值,直接输出
    LL res = 0;
    for(int i=0 ; i< 1<<n ; i ++)
    {
        int cnt = 0;
        for(int k=0 ; k<n; k ++)
        {
            if(i>>k & 1) cnt++;
        }

        if(cnt == m)
        {
            for(int j=0 ; j<n; j ++)
            {
                res = max(res , f[i][j]);
            }
        }
    }

    cout << res << endl;

    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值