算法
01背包+并查集
思路
既然这样,那这道题是否可以转换为01背包呢?
答案很明显是可以的。可以利用并查集,将这m组配对购买的商品划到一个集合里,这样就可以确定买了其中一个就得买另一个。
最后就是01背包啦!
代码
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; int father[20001],c[20001],w[20001],f[20001]; int n,m,k,x,y; int find(int x) //并查集 { return x==father[x]?x:father[x]=find(father[x]); } int main() { scanf("%d%d%d",&n,&m,&k); for (int i=1;i<=n;i++) { scanf("%d%d",&w[i],&c[i]); father[i]=i; //初始化 } for (int i=1;i<=m;i++) { scanf("%d%d",&x,&y); if (find(x)!=find(y)) father[find(y)]=find(x); //划为同一集合 } for (int i=1;i<=n;i++) if (father[i]!=i) //如果买了这一件商品就得买另一件商品 { c[find(i)]+=c[i]; w[find(i)]+=w[i]; //划为同一集合 c[i]=w[i]=0; //清零,不清零就可能会造成重复购买一件商品 } for (int i=1;i<=n;i++) for (int j=k;j>=w[i];j--) f[j]=max(f[j],f[j-w[i]]+c[i]); //01背包 printf("%d ",f[k]); return 0; }