其他分享
首页 > 其他分享> > 搭配购买 题解

搭配购买 题解

作者:互联网

搭配购买

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