P1455 搭配购买

题目描述

明天就是母亲节了,电脑组的小朋友们在忙碌的课业之余挖空心思想着该送什么礼物来表达自己的心意呢?听说在某个网站上有卖云朵的,小朋友们决定一同前往去看看这种神奇的商品,这个店里有 nn 朵云,云朵已经被老板编号为 1,2,3,...,n1,2,3,...,n,并且每朵云都有一个价值,但是商店的老板是个很奇怪的人,他会告诉你一些云朵要搭配起来买才卖,也就是说买一朵云则与这朵云有搭配的云都要买,电脑组的你觉得这礼物实在是太新奇了,但是你的钱是有限的,所以你肯定是想用现有的钱买到尽量多价值的云。

输入格式

第一行输入三个整数,n,m,wn,m,w,表示有 nn 朵云,mm 个搭配和你现有的钱的数目。

第二行至 n+1n+1 行,每行有两个整数, c_i,d_ici​,di​,表示第 ii 朵云的价钱和价值。

第 n+2n+2 至 n+1+mn+1+m 行 ,每行有两个整数 u_i,v_iui​,vi​。表示买第 u_iui​ 朵云就必须买第 v_ivi​ 朵云,同理,如果买第 v_ivi​ 朵就必须买第 u_iui​ 朵。

输出格式

一行,表示可以获得的最大价值。

输入输出样例

输入 #1复制

5 3 10
3 10
3 10
3 10
5 100
10 1
1 3
3 2
4 2

输出 #1复制

1

说明/提示

  • 对于 30\%30% 的数据,满足 1 \le n \le 1001≤n≤100;
  • 对于 50\%50% 的数据,满足 1 \le n, w \le 10^31≤n,w≤103,1 \le m \le 1001≤m≤100;
  • 对于 100\%100% 的数据,满足 1 \le n, w \le 10^41≤n,w≤104,0 \le m \le 5 \times 10^30≤m≤5×103。

1.这是一道并查集加动态规划得题目。

2.我刚开始的思路是,找祖宗的同时,把价格和价值加到祖宗上去计算,然后动态规划用的也是二维背包。但是只AC了50%,一个案列WA,四个MLE(下面是那个50分的代码)。 

#include<stdio.h>
#define N 10010
#define M 5010
int n,m,w;
int dp[N][N];
typedef struct node
{
	int dad;
	int c;
	int d;
}NODE;
NODE a[N];
int getf(int x)
{
	if(a[x].dad==x) return x;
	else return getf(a[x].dad);
}
int merge(int x,int y)
{
	int p,q;
	p=getf(x);
	q=getf(y);
	if(p!=q)
	{
		a[q].dad=a[p].dad;
		a[p].c+=a[q].c;
		a[p].d+=a[q].d;
	}
}
int max(int a,int b)
{
	if(a>b) return a;
	return b;
}
int fun()
{
	int i,j,k;
	for(i=1;i<=n;i++)
	{
		k=getf(i);
		for(j=1;j<=w;j++)
		{
			if(j<a[k].c) dp[i][j]=dp[i-1][j];
			else dp[i][j]=max(dp[i-1][j],dp[i-1][j-a[k].c]+a[k].d);
		}
	}
	printf("%d\n",dp[n][w]);
}
int main()
{
	int i,x,y;
	scanf("%d%d%d",&n,&m,&w);
	for(i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i].c,&a[i].d);
		a[i].dad=i;
	}
	for(i=0;i<m;i++)
	{
		scanf("%d%d",&x,&y);
		merge(x,y);
	}
//	for(i=1;i<=n;i++)
//		printf("%d ",a[i].dad);
//	puts("");
	fun();
	return 0;
}

3.其实这一题是可以不用二维背包的,一维背包也是可以的,我们控制好价格和价值的关系即可。

4.用一维背包的话,大家可以看看一维背包的写法:

采药(c语言贪心算法)_lxh0113的博客-CSDN博客_算法采药问题

我们在使用  i   的过程中,去找 i 的祖宗,如果祖宗在book数组(该数组是来看当前是否已经取过值,因为我们会把同属于一个集合的价格和价值一起计算,下次是没有必要再去计算一遍,再计算一遍也会出错),book数组标记为 1 的时候我们是不需要管它的,然后就是book数组为0的情况,我们需要再把云朵数组遍历一遍,找到和 i 祖宗一样的,累加它。 

 

5.我们使用 累加的价格 p 累加的价值 q,去直接代入dp数组使用。就是下面这样,只不过改了形式。

6.最后输出dp[w]即可

 代码如下:

#include<stdio.h>
#define N 10010
#define M 5010
int n,m,w;
int dp[N],book[N]={0};
typedef struct node
{
	int dad;
	int c;
	int d;
}NODE;
NODE a[N];
int getf(int x)
{
	if(a[x].dad==x) return x;
	else return getf(a[x].dad);
}
int merge(int x,int y)
{
	int p,q;
	p=getf(x);
	q=getf(y);
	if(p!=q)
	{
		a[q].dad=a[p].dad;
	}
}
int pd(int x,int y)
{
	int p,q;
	p=getf(x);
	q=getf(y);
	if(p==q) return 1;
	else return 0;//是一个集合
}
int max(int a,int b)
{
	if(a>b) return a;
	return b;
}
int fun()
{
	int i,j,k,p,q,r;
	for(i=1;i<=n;i++)
	{
		k=getf(i);
		if(book[k]==0)
		{
			p=q=0;
			for(r=1;r<=n;r++)
			{
				if(pd(r,k)==1)
				{
					p+=a[r].c;
					q+=a[r].d;
					book[r]=1;
				}
			}
			for(j=w;j>=p;j--)
				dp[j]=max(dp[j],dp[j-p]+q);
		}
	}
	printf("%d\n",dp[w]);
//	for(i=1;i<=w;i++)
//		printf("%d ",dp[i]);
}
int main()
{
	int i,x,y;
	scanf("%d%d%d",&n,&m,&w);
	for(i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i].c,&a[i].d);
		a[i].dad=i;
	}
	for(i=0;i<m;i++)
	{
		scanf("%d%d",&x,&y);
		merge(x,y);
	}
//	for(i=1;i<=n;i++)
//		printf("%d ",a[i].dad);
//	puts("");
	fun();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值