zoukankan      html  css  js  c++  java
  • 搭配购买

    搭配购买

    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;
    }
    

  • 相关阅读:
    List数据去重的五种有效方法
    select 1 from ... sql语句中的1代表什么意思?
    gitlab 创建一个空的分支 将本地代码推到特定分支
    Error running 'dt-assets-monitor [clean]': Cannot run program "C:Program Files (x86)Javajdk1.8.0_73injava.exe" (in directory "E:codedt-assets-monitor")
    Git SSH Key 生成步骤
    Git,GitHub与GitLab的区别
    聊聊TCP Keepalive、Netty和Docker
    centos7设置非图形界面
    PHP mysqli 使用预处理语句防注入
    用传纸条讲 HTTPS
  • 原文地址:https://www.cnblogs.com/Eleven-Qian-Shan/p/13111994.html
Copyright © 2011-2022 走看看