状压DP题目整理

简单题

D. Cunning Gena

传送门

#include <bits/stdc++.h>
 
using namespace std;
 
using ll = long long;
#define MAXN 22
ll dp[1<<MAXN];
int x[150];
ll k[150];
int M[150];
int d[150];
int id[150];
ll n,m,b;
int main()
{
    
    
    scanf("%lld%lld%lld",&n,&m,&b);
    int lim=1<<m;
    for(int i=1;i<=n;i++)
    {
    
    
        scanf("%d%lld%d",x+i,k+i,M+i);
        for(int j=0;j<M[i];j++)
        {
    
    
            int t;scanf("%d",&t);
            d[i]|=1<<(t-1);
        }
        id[i]=i;
    }
    sort(id+1,id+1+n,[=](int x,int y)->bool{
    
    return k[x]<k[y];});
    for(int i=0;i<lim;i++)
        dp[i]=2e18;
    //cout<<dp[0]<<endl;
    dp[0]=0;
    ll ans=dp[1];
    ll inf=ans;
    for(int t=1;t<=n;t++)
    {
    
    
        int i=id[t];
        for(int j=0;j<lim;j++)
        {
    
    
            if(dp[j]==inf)continue;
            dp[j|d[i]]=min(dp[j|d[i]],dp[j]+1ll*x[i]);
        }
        ans=min(ans,dp[lim-1]+1ll*b*k[i]);
    }
    if(ans==inf)ans=-1;
    cout<<ans<<endl;
}

思维好题

题意:给你n个物品(n<=24),每个物品有一个体积 v i v_i vi,一个箱子最多能容纳V体积,问最少需要几个箱子?

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define MAXN 24
int d[1<<MAXN];
int p[1<<MAXN];
int a[1<<MAXN];
int s[MAXN+3];
int lowbit(int x)
{
    
    
    return x&(-x);
}
int main() {
    
    
    ll n,k;scanf("%lld%lld",&n,&k);
    for(int i=0;i<n;i++) {
    
    
        scanf("%d", a +(1<<(i)));
    }
    int lim=1<<n;
    s[0]=1;
    for(int i=1;i<n;i++)
        s[i]=s[i-1]<<1;
    for(int i=0;i<lim;i++) {
    
    
        d[i]=p[i] =30;
    }
    d[0]=0;
    p[0]=k;
    for(int j=1;j<lim;j++) {
    
    
        int tmp=j;
        while(tmp)
        {
    
    
            int cur=lowbit(tmp);
            int nxt = j^cur;
            int cnt = d[nxt];
            int mod = p[nxt];
            if (mod + a[cur] > k)
            {
    
    
                cnt++;
                mod = a[cur];
                //我一开始写的是mod=min(mod,a[cur]);,但这样也可以过
            }
            else
                mod += a[cur];
            if (cnt < d[j]|| cnt == d[j]&& mod < p[j]) {
    
    
                d[j] =cnt;
                p[j]=mod;
            }
            tmp-=cur;
        }
    }
    cout<<d[lim-1]-1<<endl;
}

卡常数有点毒瘤,首先我用了一个数组表示一个状态的最小需要体积。
那么用到的箱子数量就是dp[i]/k+(dp[i]%k>0),但是由于用到了除法常数有点大。
所以我比赛时候被卡了。
正解应该是开两个数组。。。。
一个记录状态的箱子数量,一个记录状态的当前使用箱子已用体积。
这样就可以避免除法了。
然后,这里有一个很妙的点在于:
其实这个2^n
n得递推,做到了类似于全排列n!的效果。
即囊括了所有可能的先后顺序。
然后这题还卡常数,实测lowbit快于每一位的枚举,这样才100%通过
*

猜你喜欢

转载自blog.csdn.net/weixin_43353639/article/details/108021193