【hdu3080】01背包(容量10^7)

【题意】n个物品,有wi和vi,组成若干个联通块,只能选取一个联通块,问得到m的价值时最小要多少空间(v)。n<=50,v<=10^7

【题解】

先用并查集找出各个联通块。

这题主要就是v太大了,跟以往的背包不同。

我们回想01背包,f[j+v[i]]=max(f[j]+w[i]);

在这里面很明显很多状态都没有用。

优化:如果有2个状态,v1<=v2 && w1>=w2 则(v2,w2)这个状态是没有用的。

我们回到滚动数组中:

f[i][j+v[i]]=max(f[i^1][j]+w[i]);

那么我们可以用两个优先队列,q0存以前的f[i-1],q1存当前的f[i]。

我们在求f[i]的时候,就把q0一个个pop出来,更新后放到q1里面去。

做完i,我们要把q1放到q0,然后做i+1。

在把q1放到q0的时候就把没用的状态去掉(对于(v,val),先按val从大到小排序,再按v从小到大排序,对同样的val取最小的v)。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<vector>
 8 using namespace std;
 9
10 typedef long long LL;
11 const LL N=60,INF=(LL)1e15;
12 LL n,m,fa[N],t[N],w[N],c[N][N];
13 struct node{LL v,val;};
14
15 struct cmp
16 {
17     bool operator () (node &x,node &y)
18     {
19         if(x.val==y.val) return x.v<y.v;
20         return x.val<y.val;
21     }
22 };
23
24 priority_queue<node,vector<node>,cmp> q0,q1;
25
26 LL findfa(LL x)
27 {
28     if(fa[x]==x) return x;
29     return findfa(fa[x]);
30 }
31
32 LL minn(LL x,LL y){return x<y ? x:y;}
33
34 int main()
35 {
36     freopen("a.in","r",stdin);
37     freopen("me.out","w",stdout);
38     int T,cas=0;
39     scanf("%d",&T);
40     while(T--)
41     {
42         scanf("%d%d",&n,&m);
43         for(int i=1;i<=n;i++) fa[i]=i;
44         for(int i=1;i<=n;i++)
45         {
46             int num,xx;
47             scanf("%lld%lld%d",&t[i],&w[i],&num);
48             for(int j=1;j<=num;j++)
49             {
50                 scanf("%d",&xx);
51                 fa[findfa(i)]=findfa(xx);
52             }
53         }
54         memset(c,0,sizeof(c));
55         for(int i=1;i<=n;i++)
56         {
57             fa[i]=findfa(i);
58             c[fa[i]][++c[fa[i]][0]]=i;
59         }
60         node x,p,f;
61         LL ans=INF;
62         for(int k=1;k<=n;k++) if(c[k][0])
63         {
64             // printf("k = %d\n",k);
65             while(!q0.empty()) q0.pop();
66             while(!q1.empty()) q1.pop();
67             x.v=0;x.val=0;
68             q0.push(x);
69             for(int j=1;j<=c[k][0];j++)
70             {
71                 int i=c[k][j];
72                 while(!q0.empty())
73                 {
74                     x=q0.top();q0.pop();q1.push(x);
75                     f.v=x.v+t[i];
76                     f.val=x.val+w[i];
77                     if(f.v>=ans) continue;
78                     if(f.val>=m) {ans=minn(ans,f.v);continue;}
79                     q1.push(f);
80                 }
81                 LL mn=INF;
82                 while(!q1.empty())
83                 {
84                     x=q1.top();q1.pop();
85                     if(x.val>=m) ans=minn(ans,x.v);
86                     if(x.v<mn) mn=x.v,q0.push(x);
87                     // printf("v = %lld  val = %lld\n",x.v,x.val);
88                 }
89             }
90             // f[i^1][v+c[i]]=maxx(f[i^1][v+c[i]],f[i][v]+w[i]]);
91         }
92         if(ans<INF) printf("Case %d: %lld\n",++cas,ans);
93         else printf("Case %d: Poor Magina, you can‘t save the world all the time!\n",++cas);
94     }
95     return 0;
96 }
时间: 2024-10-14 16:10:26

【hdu3080】01背包(容量10^7)的相关文章

hdu 3339 In Action (最短路径+01背包)

In Action Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3869    Accepted Submission(s): 1237 Problem Description Since 1945, when the first nuclear bomb was exploded by the Manhattan Project t

NYOJ 289 苹果(01背包)

苹果 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 ctest有n个苹果,要将它放入容量为v的背包.给出第i个苹果的大小和价钱,求出能放入背包的苹果的总价钱最大值. 输入 有多组测试数据,每组测试数据第一行为2个正整数,分别代表苹果的个数n和背包的容量v,n.v同时为0时结束测试,此时不输出.接下来的n行,每行2个正整数,用空格隔开,分别代表苹果的大小c和价钱w.所有输入数字的范围大于等于0,小于等于1000. 输出 对每组测试数据输出一个整数,代表能放入背包的苹

(hdu step 3.3.1)Big Event in HDU(01背包:N件物品放在容量为V的背包中,第i件物品的费用是c[i],价值是w[i]。问所能获取的最大价值)

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

HDU 3339 In Action【最短路+01背包模板/主要是建模看谁是容量、价值】

 Since 1945, when the first nuclear bomb was exploded by the Manhattan Project team in the US, the number of nuclear weapons have soared across the globe. Nowadays,the crazy boy in FZU named AekdyCoin possesses some nuclear weapons and wanna destroy

HDU - 2602 Bone Collector(01背包讲解)

题意:01背包:有N件物品和一个容量为V的背包.每种物品均只有一件.第i件物品的费用是volume[i],价值是value[i],求解将哪些物品装入背包可使价值总和最大. 分析: 1.构造二维数组:dp[i][j]---前i件物品放入一个容量为j的背包可以获得的最大价值. dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - volume[i]] + value[i]);---(a) (1)dp[i - 1][j]---不放第i件物品,因此前i件物品放入一个容量为

超大背包(挑战编程之01背包)

先来温习01背包: 01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2--Wn,与之相对应的价值为P1,P2--Pn. 求出获得最大价值的方案. 注意:在本题中,所有的体积值均为整数. 思路: 考虑用动态规划的方法来解决,这里的:阶段是:在前N件物品中,选取若干件物品放入背包中:状态是:在前N件物品中,选取若干件物品放入所剩空间为W的背包中的所能获得的最大价值:决策是:第N件物品放或者不放:由此可以写出动态转移方程:我们用f[i,j]表示在前 i 件物品中选择若干件放

[CF837D] Round Subset(滚动数组,01背包)

题目链接:http://codeforces.com/contest/837/problem/D 题意:n个数里选k个数,使得它们的乘积末尾0个数最多. 只需要统计每个数的2和5的数量,一个作为容量,一个作为价值.f(i,k,j)表示前i个数选k个,一共有j个2的时候,5最多有几个. 外层枚举前i个数,内层做01背包就可以.但是会MLE,所以滚动数组. 特别注意的是,滚动数组在滚动的时候要拷贝整层,原因是我在更新01背包的时候没有及时复制... 还有f要注意当前层一定要从之前存在的状态更新过来,

0-1背包-回溯法

算法描述: 0-1背包的回溯法,与装载问题的回溯法十分相似.在搜索解空间树时,只要其左儿子结点是一个可行结点,搜索就进入其左子树.当右子树中有可能包含最优解时才进入右子树进行搜索.否则将右子树剪去. 计算右子树上界的更好算法是: 将剩余物品依其单位重量价值排序,然后依次装入物品,直至装不下时,再装入该物品的一部分而装满背包. 算法实现: 由Bound函数计算当前节点处的上界. 类Knap的数据成员记录解空间树的节点信息,以减少参数传递及递归调用所需的栈空间. 在解空间树的当前扩展结点处,仅当要进

CSU 1547 Rectangle(dp、01背包)

题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1547 Description Now ,there are some rectangles. The area of these rectangles is 1* x or 2 * x ,and now you need find a big enough rectangle( 2 * m) so that you can put all rectangles into it(th