搭配购买 题解
作者:互联网
搭配购买
https://www.luogu.com.cn/problem/P1455
前言:
这道题...emm...其实很简单,只是有些小细节和思路想要记录一下,于是就有了这篇题解quq
题目简述:
给定n朵云(物品)的价格和价值,再给定m个捆绑关系以及你所拥有的总钱数
每一个捆绑关系给定u、v两个物品,表示购买u物品必须买v物品,同理,购买v物品也必须买u物品
要求求出在你所能承担的价格以内,购买得到的最大总价值是多少
算法:
并查集&01背包
解题思路:
(1)如果没有物品间的捆绑关系,那么这道题就是特别简单以及单纯的01背包问题
(2)难道有了捆绑关系就没办法使用01背包了吗?当然不是,我们可以将捆绑关系转换一下,然后就可以使用01背包求解了
(3)那如何转换呢?——并查集,转换思路如下:
①对于每一个捆绑关系,我们将这两个物品合并在一棵树上
②处理完所有捆绑关系后,我们再从1循环到n,判断有几棵树,再累计每棵树的总价格和总价值
③处理完后,我们就能够用01背包的模板解决这道题了
(4)但是,你会发现,如果是开另外一个数组找树之后再循环01背包,会T到只有70pts,所以我们还需要优化,而且优化肯定就是在处理每一棵树上面了
(5)所以我们在累加每一棵树的总价格和总价值时,直接存在根节点、同时将子节点清零,最后对每一棵树的根节点进行01背包即可
PS:当然,大概只有我会选择优化之前处理每一棵树的复杂方法QAQ
代码Code:
(1)先给出70pts的代码(小声,洛谷吸口氧还是能过的)
#include <bits/stdc++.h>
using namespace std;
int n,m,W,u,v,tot,fa[10005],vis[50010],f[50010];
struct node {
int w,v,p;
} a[50010];
struct nodes {
int wt,vt;
} sum[50010];
inline int find_fa(int x) {
if(fa[x]==x) return x;
return fa[x]=find_fa(fa[x]);
}
int main() {
scanf("%d%d%d",&n,&m,&W);
for(register int i=1;i<=n;i++) {
fa[i]=i;
scanf("%d%d",&a[i].w,&a[i].v);
}
for(register int i=1;i<=m;i++) {
scanf("%d%d",&u,&v);
int uu=find_fa(u);
int vv=find_fa(v);
fa[uu]=vv;
}
for(register int i=1;i<=n;i++) {
if(vis[find_fa(i)]==0) {
sum[find_fa(i)].wt=a[i].w;
sum[find_fa(i)].vt=a[i].v;
vis[find_fa(i)]=1;
a[i].p=2;
}
else {
sum[find_fa(i)].wt+=a[i].w;
sum[find_fa(i)].vt+=a[i].v;
}
}
for(register int i=1;i<=n;i++) {
if(a[i].p==2) {
for(register int j=W;j>=sum[find_fa(i)].wt;j--) {
f[j]=max(f[j],f[j-sum[find_fa(i)].wt]+sum[find_fa(i)].vt);
}
}
}
printf("%d",f[W]);
return 0;
}
(2)再给出100pts的正解代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,W,u,v,fa[10005],f[50010];
struct node {
int w,v;
} a[50010];
inline int find_fa(int x) {
if(fa[x]==x) return x;
return fa[x]=find_fa(fa[x]);
}
int main() {
scanf("%d%d%d",&n,&m,&W);
for(register int i=1;i<=n;i++) {
fa[i]=i;
scanf("%d%d",&a[i].w,&a[i].v);
}
for(register int i=1;i<=m;i++) {
scanf("%d%d",&u,&v);
int uu=find_fa(u);
int vv=find_fa(v);
fa[uu]=vv;
}
for(register int i=1;i<=n;i++) {
if(find_fa(i)!=i) {
a[find_fa(i)].v+=a[i].v;
a[find_fa(i)].w+=a[i].w;
a[i].v=a[i].w=0;
}
}
for(register int i=1;i<=n;i++) {
for(register int j=W;j>=a[i].w;j--) {
f[j]=max(f[j],f[j-a[i].w]+a[i].v);
}
}
printf("%d",f[W]);
return 0;
}
标签:01,return,fa,搭配,题解,50010,int,购买,find 来源: https://www.cnblogs.com/Eleven-Qian-Shan/p/13111994.html