其他分享
首页 > 其他分享> > 做题记录2021.7.23

做题记录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