状态压缩dp

时间:2019-10-29
本文章向大家介绍状态压缩dp,主要包括状态压缩dp使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

在看到这个毒瘤题目之前我一直觉得吧,状态里头怎么能够有指数级别的变量呢???

然后我就花了至少一个小时的时间想有没有更好的方法“让状态转移有序化”。虽然数据范围很小但我就是不想这样搞。结束后我去问了老师才知道这居然是很常见的操作。一般变量范围在指数级别的都能用状态压缩来减少……减少什么东西呢……反正都能压缩,要是不能压缩你也超时。

状态压缩的意思是把一些需要多个二进制位保存的状态利用一个整数来保存,避免了位数不同时出现的尴尬局面。然而只知道这个什么用都没有。

下面来看看例题吧。

题目描述
小c现在有M(1≤M≤20)道题目不会写,他决定找大牛们要代码。
这N(1≤N≤100)位大牛每人都写了若干题,并且提出了各自要求的报酬,给钱就能获得他的所有代码。
小c虽然是笨蛋,但已经不会随便提交别人的代码了,他只提交自己能看懂的代码。
然而,大牛们的代码风格千奇百怪,如果智力不达标,是根本看不懂的。
所以小c还要去上智力提升课程。一节课能提升1点智力,学费是K(1≤K≤109)元。
(他现在的智力为0)
他希望花最少的钱解决所有题目。

输入
第一行,整数N,M,K.
下面共2N行,每两行描述一位大牛.
第1行,整数xi,qi,mi,分别表示报酬要求,智力要求,解决的题目数
(1 ≤ xi,qi ≤ 109;1 ≤ mi ≤ M)
第2行,mi个整数,表示他解决的题。题目标号为1到M

输出
一个整数,表示解决所有题目需要的最少花费。若无法完成,输出-1

样例1
输入

2 2 1
100 1 1
2
100 2 1
1

输出

202

样例2
输入

1 2 1
1 1 1
1

输出

-1

样例3
输入

3 2 5
100 1 1
1
100 1 1
2
200 1 2
1 2

输出

205

大概就是这样,除了智商和钱好像都没有什么有序的变量可供作为状态,所以就只能捡好的用咯。
因为我们只关心在所有题都做好的情况下的智商,所以我们可以使大牛按照智商排序以求结束时的智商是在只雇用前面这些人的情况下智商最低的,也因为这样,我们不把智商纳入状态中,因为这样会让推进变得无序。虽然看似有些无脑但是这样对于最优解的处理就很好搞了。
用一个整数保存做了什么题,数量级是$$2^{20}$$,大概在两百万的样子,开还是开的下的。

确定了状态剩下的就是一个0-1背包问题了。但是还有一个智商需要解决,由于我们只关心最终把所有题完成也就是(1<<m)-1这个状态时的智商,只需要将当前人的智商(也就是最低智商)乘以课的价钱加上状态就好了。虽然考试的时候几乎想不到就是了。

#include<bits/stdc++.h>
using namespace std;
const long long inf=1900000000000000000;
long long n,m,k,can,ans=inf;
long long dp[(1<<20)-1];
struct per{
    long long x,m,sol;
    int q;
}cal[105];
bool cmp(per a,per b){
    return a.q<b.q;
}
int main(){
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
        cin>>cal[i].x>>cal[i].q>>cal[i].m;
        for(int j=1;j<=cal[i].m;j++){
            cin>>can;
            cal[i].sol|=1<<can-1;
        }
    }
    sort(cal+1,cal+n+1,cmp);
    for(int i=1;i<=(1<<m)-1;i++)
        dp[i]=inf;
    for(int i=1;i<=n;i++){
        for(int j=(1<<m)-1;j>=0;j--)
            if(dp[j]<inf&&dp[j|cal[i].sol]>dp[j]+cal[i].x)
                dp[j|cal[i].sol]=dp[j]+cal[i].x;
        ans=min(ans,dp[(1<<m)-1]+cal[i].q*k);
    }
    // cout<<dp[1]<<" "<<dp[2]<<" "<<dp[3]<<'\n';
    if(ans==inf)
        cout<<-1;
    else cout<<ans;
    return 0;
}

原文地址:https://www.cnblogs.com/Schwarzkopf-Henkal/p/11759372.html