zoukankan      html  css  js  c++  java
  • 【BZOJ3717】[PA2014]Pakowanie 状压DP

    【BZOJ3717】[PA2014]Pakowanie

    Description

    你有n个物品和m个包。物品有重量,且不可被分割;包也有各自的容量。要把所有物品装入包中,至少需要几个包?

    Input

    第一行两个整数n,m(1<=n<=24,1<=m<=100),表示物品和包的数量。
    第二行有n个整数a[1],a[2],…,a[n](1<=a[i]<=10^8),分别表示物品的重量。
    第三行有m个整数c[1],c[2],…,c[m](1<=c[i]<=10^8),分别表示包的容量。

    Output

    如果能够装下,输出一个整数表示最少使用包的数目。若不能全部装下,则输出NIE。

    Sample Input

    4 3
    4 2 10 3
    11 18 9

    Sample Output

    2

    题解:一开始想到了栅栏那题,以为是爆搜+剪枝,结果狂TLE不止,后来发现是状压。。。

    显然我们应该贪心的从容量较大的包开始选,然后用f[S]表示已经用过的物品状态为S时,最少用几个包,g[S]表示在用的包最少的前提下,最后一个包的最大剩余容量。

    转移时用到了一些卡常小技巧~

     

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,m,N;
    int f[1<<24],g[1<<24],w[1<<24],c[110];
    int main()
    {
    	scanf("%d%d",&n,&m),N=(1<<n)-1;
    	int i,j,k,S;
    	for(i=0;i<n;i++)	scanf("%d",&w[i]);
    	for(i=n-1;i>=0;i--)	w[1<<i]=w[i];
    	for(i=1;i<=m;i++)	scanf("%d",&c[i]);
    	sort(c+1,c+m+1);
    	f[0]=m+1,g[0]=0;
    	for(i=1;i<=N;i++)
    	{
    		for(j=i;j;j-=k)
    		{
    			k=j&-j,S=i^k;
    			if(g[S]>=w[k]&&(f[S]>f[i]||(f[S]==f[i]&&g[S]>g[i]+w[k])))	f[i]=f[S],g[i]=g[S]-w[k];
    			else	if(c[f[S]-1]>=w[k]&&(f[S]>f[i]+1||(f[S]==f[i]+1&&c[f[i]]>g[i]+w[k])))	f[i]=f[S]-1,g[i]=c[f[i]]-w[k];
    		}
    	}
    	if(!f[N])	printf("NIE");
    	else	printf("%d",m+1-f[N]);
    	return 0;
    }

     

  • 相关阅读:
    日常
    hdoj 5690 All X (快速幂+取模)
    hdoj 4004 The Frog's Games(二分)
    Mac androidStudio cannot resolve corresponding JNI function
    Mac 切换JDK版本
    MAC系统 如何显示隐藏的文件(文件夹)
    C 读写文件以及简单的文件加密
    C 双向链表的简单排序实现
    Android ViewDragHelper详解
    android Toast的内容过长,如何居中显示?
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7787818.html
Copyright © 2011-2022 走看看