hdu 4381(背包变形)

题意:

给定n个块,编号从1到n,以及m个操作,初始时n个块是白色。

操作有2种形式:

1 ai xi : 从[1,ai]选xi个块,将这些块涂白。

2 ai xi:从[ai,n]选xi个块,将这些块涂白。

可以忽略某些操作且如果区间内没有足够的黑块(黑块用于涂白),则不能进行这个操作。

分析:

写写画画一看就知道这道题是一个背包问题。

“恰好装满背包”。

以下摘自题解:

本题难点在于正确处理两种操作,不妨假设只有一种操作,那么这种操作如果是1的话那么就把操作按照a从小到大排序,每次都尽量往最左边涂,如果是2的话则类似的涂到最右边,但本题两种操作都出现了。

先考虑第一问:

我们把所有的操作按类别区分开,假设所有的1操作尽量用上能从1涂到a格子,所有的2操作尽量用上能从b格子涂到n,假设a<b,那么答案显然是a+n-b+1。那么假设a>=b,那么假设1操作从1涂到x,那么2操作一定会从n尽量往左边涂,直到x为止。最后两边的总和就是答案。

由上不难想到一个DP,l[i][j]表示用了前i种1操作,从1涂到j的最小操作数,转移l[i][j]=min(l[i][j],l[i-1][j-ope[i].x]+1)(ope[i].x<=j<=ope[i].a),类似的,我们可以得到r[i][j]表示用2操作从j涂到n需要的最小操作数。dp复杂度O(n*m)。(这个背包也可以压缩一维,后面的l,r均为1维的状态)

那么我们倒着枚举涂色最大的数目,假设为k,这个数目必然由1操作贡献一部分,由2操作贡献一部分(也可能一个贡献全部,另一个为0),那么我们枚举1操作涂到了i,那么2操作必然涂到了n-(k-i)+1,如果l[i]和r[n-(k-i)+1]均有值,那么说明这个最大数目是可达的,即是第一问的答案。枚举复杂度O(n*n)。

再考虑第二问:

现在我们已经知道最大数目了,这个数目是由操作1和操作2一起贡献的,那么我们仍然可以枚举操作1涂到了i,那么操作2涂到了n-(ans-i)+1,如果l[i]和r[n-(k-i)+1]均有值,那么其和可以用来更新第二问的答案,最后第二问的答案为所有合法方案需操作数的最小值。枚举复杂度O(n*n)。

代码实现:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>

using namespace std;
const int maxn = 2005;
struct node{
    int aa,cor;
    node(){}
    node(int _aa,int _cor){
       aa = _aa;   cor = _cor;
    }
}x1[maxn],x2[maxn];
int n,m;
int dp1[maxn],dp2[maxn];
int sumx1,sumx2;

bool cmp(const node &p,const node &q){
    return p.aa < q.aa;
}

int min(int a,int b)
{
    return a<b?a:b;
}

int main()
{
    int cas,ta=1;
    scanf("%d",&cas);
    while(cas--){
         int i,j;
         scanf("%d%d",&n,&m);

         sumx1 = sumx2 = 1;
         for(i=0; i<m; i++){
             int key,yy,z;
             scanf("%d%d%d",&key,&yy,&z);
             if(key == 1){
                x1[sumx1++] = node(yy,z);
             }else{
                x2[sumx2++] = node(n+1-yy,z);
             }
         }
         sort(x1+1,x1+sumx1,cmp);
         sort(x2+1,x2+sumx2,cmp);
         memset(dp1,0x3f,sizeof(dp1));
         memset(dp2,0x3f,sizeof(dp2));

         dp1[0] = dp2[0] = 0;
         for(i=1; i<sumx1; i++){
             for(j=x1[i].aa; j>=x1[i].cor; j--){
                dp1[j] = min(dp1[j],dp1[j-x1[i].cor]+1);
             }
         }

         for(i=1; i<sumx2; i++){
             for(j=x2[i].aa; j>=x2[i].cor; j--){
                dp2[j] = min(dp2[j],dp2[j-x2[i].cor]+1);
             }
         }

         int ans = 0,anssum = 0,tmp;
         for(i=1; i<=n; i++){
            for(j=0; j<=i; j++){
               tmp = dp1[j] + dp2[i-j];
               if(tmp <= m){
                  if(ans != i){
                    ans = i;   anssum = tmp;
                  }else if(tmp < anssum){
                      anssum = tmp;
                  }
               }
            }
         }

         printf("Case %d: %d %d\n",ta++,ans,anssum);
    }
    return 0;
}

hdu 4381(背包变形)

时间: 2024-10-25 17:39:44

hdu 4381(背包变形)的相关文章

hdu 4381 背包

http://acm.hdu.edu.cn/showproblem.php?pid=4381 Problem Description There are n boxes in one line numbered 1 to n, at the beginning, all boxes are black. Two kinds of operations are provided to you: 1 ai xi :You can choose any xi black boxes in interv

HDU 1171 Big Event in HDU (多重背包变形)

Big Event in HDU Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 27961    Accepted Submission(s): 9847 Problem Description Nowadays, we all know that Computer College is the biggest department

HDU 2955 Robberies --01背包变形

这题有些巧妙,看了别人的题解才知道做的. 因为按常规思路的话,背包容量为浮点数,,不好存储,且不能直接相加,所以换一种思路,将背包容量与价值互换,即令各银行总值为背包容量,逃跑概率(1-P)为价值,即转化为01背包问题. 此时dp[v]表示抢劫到v块钱成功逃跑的概率,概率相乘. 最后从大到小枚举v,找出概率大于逃跑概率的最大v值,即为最大抢劫的金额. 代码: #include <iostream> #include <cstdio> #include <cstring>

HDU 2639 Bone Collector II(01背包变形【第K大最优解】)

Bone Collector II Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4739    Accepted Submission(s): 2470 Problem Description The title of this problem is familiar,isn't it?yeah,if you had took pa

HDU 4381 Grid

背包变形. 将操作分为了两类,可以分开处理. 可以dp处理出L[i]:L[i]=-1代表从左到右 i 长度不能被拼凑出来,L[i]!=-1表示从左到右 i 长度能被拼凑出,并且最小费用为L[i]. 反着来一次dp就可以处理出R[i]:R[i]=-1代表从右到左 n+1-i 长度不能被拼凑出来,R[i]!=-1表示从右到左 n+1-i 长度能被拼凑出,并且最小费用为R[i]. 由L[1---i] 与R[i+1---n]可以得出,以i为分割的最优解,于是,枚举 i 即可. #pragma comme

codeforce Gym 101102A Coins (01背包变形)

01背包变形,注意dp过程的时候就需要取膜,否则会出错. 代码如下: #include<iostream> #include<cstdio> #include<cstring> using namespace std; #define MAXW 15005 #define N 155 #define LL long long #define MOD 1000000007 int w1[N],w2[N]; LL dp1[MAXW],dp2[MAXW]; int main(

Wikioi 1025 01背包变形

这题多加了菜品必选编号,所以刚开始不知道怎么写,原来就把必选的处理下就行了,因为有重复,但是相同的价值与价格都一样,所以这里就直接挑出来就行了. 把不是必选的在里面用dp即可,dp之前也要把重复的舍去. 因为总价格容量为浮点数,所以先乘以10变成整数就可以用01背包了. #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <deque&

codeforces 742D Arpa&#39;s weak amphitheater and Mehrdad&#39;s valuable Hoses ——(01背包变形)

题意:给你若干个集合,每个集合内的物品要么选任意一个,要么所有都选,求最后在背包能容纳的范围下最大的价值. 分析:对于每个并查集,从上到下滚动维护即可,其实就是一个01背包= =. 代码如下: 1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <vector> 5 using namespace std; 6 const int N = 1000 + 5;

POJ 3093 Margaritas on the River Walk (0-1背包变形)

这题目的思路很巧妙,什么情况下剩下的所有物品都放不下呢?就是当前剩余物品中最小的那个也放不下.所以,先把物品按照容量从小到大排序,依次枚举当前背包为放不下的最小物品的情况. 对于当前物品i,必有1到i-1的所有物品都放进去,这时候比i大的物品谁放谁不放是不确定的.转换成0-1背包问题:把前i-1个物品都放进去以后,得到空间为tsum - sum[i-1](前缀和)的包,只要从第i+1到第n个物品中拿出一个方案填充这个包使得剩余体积小于第i个物品的体积就可以了,把总方案数累加就是结果! 注意特殊情