AcWing 1252. 搭配购买 背包问题+并查集

AcWing 1252. 搭配购买

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。

输出格式
一行,表示可以获得的最大价值。

数据范围
1≤n≤10000,
0≤m≤5000,
1≤w≤10000,
1≤ci≤5000,
1≤di≤100,
1≤ui,vi≤n
输入样例:

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

输出样例:

1

刚开始的时候我觉得这道题非常简单,把一个集合的所有价值和钱数放到父节点上,然后我们去枚举小于等于w的父节点种哪个价值最大。

刚开始的代码如下。

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e4+10;

int p[N],wi[N],ci[N];
bool st[N];

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

int main(void)
{
    int n,m,w;
    cin>>n>>m>>w;
    for(int i=1;i<=n;i++) cin>>ci[i]>>wi[i];
    for(int i=1;i<=n;i++) p[i]=i;
    while(m--)
    {
        int a,b;
        cin>>a>>b;
        int pa=find(a),pb=find(b);
        if(pa!=pb)
        {    
            ci[pa]+=ci[pb];
            wi[pa]+=wi[pb];
            p[pb]=pa;
            st[pb]=true;
        }
    }
    int res=0;
    for(int i=1;i<=n;i++)
    if(!st[i])
    {
        if(w>=ci[i])
        res=max(res,wi[i]);
    }
    cout<<res<<endl;
}

然后我的样例是过了,但是我很疑惑我的思路没有什么错误为什么没有AC呢,我推敲了一下我的代码,基本上按我的逻辑进行的,我无奈之下看了题解,才发现,最后枚举的时候是一个背包问题,我也是有点马虎,居然没发现这个细节,可见我是多么的菜。

代码AC版就出来了,还是要仔细分析题目。

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e4+10;

int p[N],wi[N],ci[N];
bool st[N];
int f[N];

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

int main(void)
{
    int n,m,w;
    cin>>n>>m>>w;
    for(int i=1;i<=n;i++) cin>>ci[i]>>wi[i];
    for(int i=1;i<=n;i++) p[i]=i;
    while(m--)
    {
        int a,b;
        cin>>a>>b;
        int pa=find(a),pb=find(b);
        if(pa!=pb)
        {    
            ci[pa]+=ci[pb];
            wi[pa]+=wi[pb];
            p[pb]=pa;
        }
    }
    for(int i=1;i<=n;i++)
    if(p[i]==i&&w>=ci[i])
    {
        for(int j=w;j>=ci[i];j--)
        f[j]=max(f[j],f[j-ci[i]]+wi[i]);
    }
    cout<<f[w];
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值