ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

搭配购买 题解

2020-06-13 10:53:59  阅读:249  来源: 互联网

标签:01 return fa 搭配 题解 50010 int 购买 find


搭配购买

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有