1387:搭配购买(buy)

本文介绍了一个结合并查集与01背包算法解决的购买云朵问题。问题中,玩家需在有限预算下,根据云朵的搭配规则和价值,最大化购买云朵的总价值。文章详细解析了问题的输入输出格式,提供了错误与正确的代码对比,帮助读者理解算法实现细节。

【题目描述】

Joe觉得云朵很美,决定去山上的商店买一些云朵。商店里有n朵云,云朵被编号为1,2,…...,n,并且每朵云都有一个价值。但是商店老板跟他说,一些云朵要搭配来买才好,所以买一朵云则与这朵云有搭配的云都要买。

但是Joe的钱有限,所以他希望买的价值越多越好。

 

【输入】

第1行n,m,w,表示n朵云,m个搭配,Joe有w的钱。

第2~n+1行,每行ci,di表示i朵云的价钱和价值。

第n+2~n+1+m行,每行ui,vi,表示买ui就必须买vi,同理,如果买vi就必须买ui。

 

【输出】

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

【输入样例】

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

【输出样例】

1

【提示】

【数据范围】

30%的数据保证:n≤100

50%的数据保证:n≤1,000;m≤100;w≤1,000

100%的数据保证:n≤10,000;0≤m≤5000;w≤10,000

并查集+01背包

错误代码:

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;
int p1[10005];
int p2[10005];
int a[10005];
int dp[10005];

int findth(int x){
    return a[x]==x?x:findth(a[x]);
}


int main()
{
    int n,m,w;
    scanf("%d %d %d",&n,&m,&w);
    for(int i=1;i<=n;i++){
        a[i]=i;
        dp[i]=0;
        scanf("%d %d",&p1[i],&p2[i]);
    }
    int x,y;
    for(int i=1;i<=m;i++){
        scanf("%d %d",&x,&y);
        a[x]=y;
        p1[findth(y)]+=p1[x];
        p2[findth(y)]+=p2[x];
    }
    int ma=0;
    //for(int i=1;i<=n;i++){
    //    cout<<i<<":"<<a[i]<<endl;
    //}

    for (int i = 1; i <= n; i++)		//n的物品的种类
	{
	    if(a[i]==i){
            //cout<<i<<endl;
            for (int j = w; j >= p1[i]; j--)		//w[]表示物品的所占的容量
            {
                dp[j] = max(dp[j], dp[j - p2[i]] + p2[i]);	//c[]表示物品的价值
                if(dp[j]>ma) ma=dp[j];
            }
	    }
	}
	//for(int i=1;i<=w;i++){
    //    cout<<i<<":"<<dp[i]<<endl;
    //}
    printf("%d\n",ma);

return 0;
}

正确代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e4 + 10;
int n, m, s;
int p[N];  //并查集数组
int w[N];
int c[N];
int f[N];

struct node
{
	int c;
	int w;
	bool flag;
}num[N];

int findth(int x)
{
	if (x == p[x]) return x;
	return p[x] = findth(p[x]);
}

void unionn(int x, int y)
{
	int xx = findth(x);
	int yy = findth(y);
	if (xx != yy) p[yy] = xx;
}
int cnt;
int ci[N];
int di[N];

int main()
{
	scanf("%d %d %d", &n, &m, &s);
	for (int i = 1;i <= n;i++) p[i] = i;  //初始化并查集
	for (int i = 1;i <= n;i++) {
		scanf("%d %d", &ci[i], &di[i]);
	}

	for (int i = 1;i <= m;i++) {
		int x, y;
		scanf("%d %d", &x, &y);
		unionn(x, y);
	}

    for (int i = 1;i <= n;i++) {  //把每个点直接连接父节点,
		findth(i);
	}

	for (int i = 1;i <= n;i++) {  //为背包建个结构体数组
		num[p[i]].w += ci[i];
		num[p[i]].c += di[i];
		num[p[i]].flag = true;   //标记
	}



	for (int i=1;i<=n;i++){   //cnt:背包种类个数
		if (num[i].flag) {
			w[++cnt] = num[i].w;
			c[cnt] = num[i].c;
		}
	}

	for (int i = 1;i <= cnt;i++) {   //01背包
		for (int j = s;j >= w[i];j--) {
			f[j] = max(f[j], f[j - w[i]] + c[i]);
		}
	}

	printf("%d\n", f[s]);

	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值