b_lg_搭配购买(并查集+01背包)

有一些云朵商品,你需要如果商品有搭配关系,则你需要购买具有搭配关系的所有云朵;
已知你的初始财富以及各物品的价钱与价值,求出最大价值

思路
这题一开始写的\(O(n^2m)\)的暴力,得分为40pt

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5, W=1e3+5;
int n,m,cap, fa[N], sz[N], f[W];
struct node {
    int cost, val;
} A[N];
int find(int u) {
    return fa[u]==u ? u : fa[u]=find(fa[u]);
}
void merge(int u, int v) {
    int fu=find(u), fv=find(v);
    if (sz[fu]>sz[fv]) {
        fa[fv]=fu;
        sz[fu]+=sz[fv];
    } else {
        fa[fu]=fv;
        sz[fv]+=sz[fu];
    }
}
bool isConn(int u, int v) {
    return find(u)==find(v);
}
int buy(int u, int& cap) {
    int tot_val=A[u].val;
    for (int i=1; i<=n; i++) if (i!=u && isConn(i,u)) {
        cap-=A[i].cost, tot_val+=A[i].val;
        if (cap<0)
            return -1;        
    }
    return tot_val;
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>n>>m>>cap;
    for (int i=1; i<=n; i++) cin>>A[i].cost>>A[i].val, fa[i]=i, sz[i]=1;
    for (int i=0; i<m; i++) {
        int u,v; cin>>u>>v;
        merge(u,v); 
    }
    for (int i=1; i<=n; i++) 
    for (int j=cap; j>=A[i].cost; j--) {
        int t=j-A[i].cost, v=buy(i,t);
        if (v!=-1)
            f[j]=max(f[j], f[t]+v);
    }
    cout<<f[cap];
    return 0;
}

直接用一个连通块的根记录总的cost、val,让子节点的cost、val变为0,这样就省去了buy函数的O(n)的检查时间

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5, W=1e3+5;
int n,m,cap, fa[N], sz[N], f[W];
struct node {
    int cost, val;
} A[N], B[N];
int find(int u) {
    return fa[u]==u ? u : fa[u]=find(fa[u]);
}
void merge(int u, int v) {
    int fu=find(u), fv=find(v);
    if (sz[fu]>sz[fv]) {
        fa[fv]=fu;
        sz[fu]+=sz[fv];
    } else {
        fa[fu]=fv;
        sz[fv]+=sz[fu];
    }
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>n>>m>>cap;
    for (int i=1; i<=n; i++) cin>>A[i].cost>>A[i].val, fa[i]=i, sz[i]=1;
    for (int i=0; i<m; i++) {
        int u,v; cin>>u>>v;
        merge(u,v);
    }
    for (int i=1; i<=n; i++) {
        int fi=find(i);
        B[fi].val+=A[i].val, B[fi].cost+=A[i].cost;
        A[i].val=0, A[i].cost=0;
    }
    for (int i=1; i<=n; i++)
    for (int j=cap; j>=B[i].cost; j--) {
        f[j]=max(f[j], f[j-B[i].cost]+B[i].val);
    }
    cout<<f[cap];
    return 0;
}
posted @ 2020-10-09 15:16  童年の波鞋  阅读(98)  评论(0编辑  收藏  举报