• 没有找零 状压dp


    没有找零 状压dp

    约翰到商场购物,他的钱包里有K(1 <= K <= 16)个硬币,面值的范围是1..100,000,000。约翰想按顺序买 N个物品(1 <= N <= 100,000),第i个物品需要花费c(i)块钱,(1 <= c(i) <= 10,000)。在依次进行的购买N个物品的过程中,约翰可以随时停下来付款,每次付款只用一个硬币,支付购买的内容是从上一次支付后开始到现在的这些所有物品(前提是该硬币足以支付这些物品的费用)。不幸的是,商场的收银机坏了,如果约翰支付的硬币面值大于所需的费用,他不会得到任何找零。请计算出在购买完N个物品后,约翰最多剩下多少钱。如果无法完成购买,输出-1。

    如果我们枚举k的全排列是肯定超时的。显然对于一种硬币的选择方案,尽可能选更多的物品更优,没有必要枚举全排列。所以(f[i])表示当前选硬币的状态为(i),在第i个物品处,用第j个硬币能到达的最远处。那么转移方程为(f[i]=f[j]+a[f[j]][k]),k可以通过i,j判断出来。别忘记要预处理a。那么时间复杂度则为(O(knlog_2n+2^kn))

    感觉状压dp就是在dp减少无用状态的前提下贪心而已。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    const int maxn=1e5+5, maxk=20;
    int k, n, coins[maxn], things[maxn], pre[maxn];
    // pre:物品的前缀和
    int a[maxn][maxk]; //在第i个位置,用第j个硬币的能到达的地方。
    int f[int(1e6)]; //一个状态最远能到达的地方
    
    int calc(int now){
        int re=0;
        for (int i=k; i>0; --i){
            re+=(1-(now&1))*coins[i];
            now>>=1;
        }
        return re;
    }
    
    int main(){
        scanf("%d%d", &k, &n);
        for (int i=1; i<=k; ++i) scanf("%d", &coins[i]);
        for (int i=1; i<=n; ++i){
            scanf("%d", &things[i]);
            pre[i]=pre[i-1]+things[i];
        }
        int t, t2;
        for (int i=1; i<=n; ++i)
            for (int j=1; j<=k; ++j){
                t=pre[i-1]+coins[j];
                a[i][j]=upper_bound(pre+i, pre+n+1, t)-pre-i;
            }
        for (int i=0; i<(1<<k); ++i){
            t=1;
            for (int j=k; j>=1; --j){ //枚举前一个状态
                if (t&i){
                    t2=i-t;
                    f[i]=max(f[i], f[t2]+a[f[t2]+1][j]);
                }
                t<<=1;
            }
        }
        int ans=0; bool flag=false;
        for (int i=0; i<(1<<k); ++i){
            if (f[i]==n&&calc(i)>ans) ans=calc(i);
            if (f[i]==n) flag=true;
        }
        printf("%d", flag?ans:-1);
        return 0;
    }
    
  • 相关阅读:
    P2P学习(三)网络传输基本知识---TURN协议
    P2P学习(三)网络传输基本知识---STUN协议(二)
    P2P学习(三)网络传输基本知识---STUN协议(一)
    P2P学习(三)网络传输基本知识
    P2P学习(二)P2P中的NAT穿越(打洞)方案详解
    如何画UML时序图
    数据大屏、报表设计器等
    SQL Server查询指定表的操作记录
    ORACLE查询当前用户的权限
    InfluxDB:集群版使用指南(Influx-proxy)
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/7701096.html
Copyright © 2020-2023  润新知