做题记录2021.7.23
作者:互联网
这题和01背包十分相似,但要求部分物品之间存在依赖关系。
由于看到u,v,所以我就想用图表示依赖关系,建图完毕后对每个未被合并的结点进行DFS或BFS,并对路径上所有点的价值和价格相加最终得到两个和sum1和sum2,产生一个新的“物品”,其价值和价格分别为sum1和sum2,加入背包里面。进行DP时从新加入的第一个物品开始。
后来发现完全没有必要这样做。直接使用一个并查集将“有关系”的物品合成一个大物品。
注意如果合并时是fa[Find(x)]=Find(y),那就是v[Find(y)]+=v[Find(x)],w[Find(y)]+=w[Find(x)]。这是因为x被合并,已经无效了,所以它的价格和价值要加到x上,不能倒过来。
代码:
#include <cstdio>
#include <algorithm>
#include <queue>
#define long long long
const int M=10001,MAX_VALUE=1001*M;
//MAX_VALUE不能设的过小
using namespace std;
vector<int> w,v;
bool vis[M];
int fa[M];
int Find(int x) {
if(x==fa[x])
return x;
fa[x]=Find(fa[x]);
return fa[x];
}
long DP(int n,int tot) {
long *dp=(long*)calloc(MAX_VALUE,8);
for(int i=1; i<=n; i++) {
if(w[i]!=-1&&v[i]!=-1) {
for(int j=tot; j>=w[i]; j--) {
dp[j]=max(dp[j],dp[j-w[i]]+(long)v[i]); //DP过程
}
}
}
return dp[tot];
}
int main() {
int n,m,money;
scanf("%d%d%d",&n,&m,&money);
v.push_back(0),w.push_back(0);
for(int i=1; i<=n; i++) {
fa[i]=i;
int c,d;
scanf("%d%d",&c,&d);
w.push_back(c);
v.push_back(d);
}
int t=0;
for(int i=0; i<m; i++) {
int x,y;
scanf("%d%d",&x,&y);
int fx=Find(x),fy=Find(y);
if(fa[fx]!=fa[fy]) {
fa[fx]=fa[fy];
w[fy]+=w[fx];
v[fy]+=v[fx];
v[fx]=w[fx]=-1;
}
}
printf("%lld",DP(n,money));
return 0;
}
标签:fx,2021.7,记录,int,23,long,fa,Find,dp 来源: https://blog.csdn.net/m0_51303687/article/details/119038801