当前位置: 代码迷 >> 综合 >> AcWing 1252. 搭配购买 背包问题+并查集
  详细解决方案

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

热度:86   发布时间:2023-11-23 13:50:43.0

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