1 条题解

  • 0
    @ 2024-2-21 15:47:59

    乍一看是背包,细看...

    哎呦!!并查集

    背包都懂吧(不懂都别看了)
    01背包模板带上,下一站并查集
    /*
    树形数据结构--并查集
    概念:有若干个集合,每个集合均为一棵树
    主要用处:处理一些合并及查询问题速度较快
    处理问题与函数:合并(merge)->将若干个点合并到一个或多个集合里(构成一棵树或森林)或将多个集合合并成一个集合
                   查询(find)->询问该子节点的根(root)
                   其他(other)->求集合数量(number)
    用fa数组存储父节点,难点便迎刃而解
    代码实现:
    查询:
    if (x!=fa[x])find(fa[x]);
    return fa[x];
    三目缩写:
    return f[x]==x?f[x]:f[x]:find(f[x]);
    合并:
    int tx=find(x);
    int ty=find(y);
    if (tx!=ty)fa[tx]=ty;
    其他:
    if(fa[x]==x)ans++;
    路径压缩:
    find函数每次查找父节点,下次再查找运行时间变慢,所以每次求出父节点便存起来
    return f[x]==x?f[x]:f[x]=find(f[x]);
    (废了吧)
    */
    #include <bits/stdc++.h>
    using namespace std;
    const int MAX=10100;//常量,常见的INT_MAX和INT_MIN都是常量
    int n,m,maxn;//n是礼品数量,m个搭配和你现有的钱的数目(背包容量)
    int w[MAX],v[MAX],dq[MAX];//w钱数(体积),v价值,dq状态(fate)
    int f[MAX];//储存父节点
    int find(int x){
    	return f[x]==x?f[x]:f[x]=find(f[x]);
    }//find函数,查找该结点的根,递归查找
    void merge(int x,int y){
    	int tx=find(x);
    	int ty=find(y);
    	if (tx!=ty)f[tx]=ty;
    }//merge函数,合并集合
    int main(){
        /*
         思路:将一个集合(树)的所有子节点加到根节点上,再做背包
        */
    	cin>>n>>m>>maxn;//读入数据
    	for (int i=1;i<=n;i++){
    		cin>>w[i]>>v[i];
    		f[i]=i; //初始化f数组(自己为根)
    	}
    	int x,y;//不用说吧
    	for (int i=1;i<=m;i++){
    		cin>>x>>y;
    		merge(x,y);//合并
    	}
    	int root;//定义树根
    	for (int i=1;i<=n;i++){
    		if (f[i]!=i){//不是根节点
    			root=find(f[i]);//找到f[i]的根
    			w[root]+=w[i];//全部加到根上
    			v[root]+=v[i];
    			w[i]=v[i]=0;//不忘成0
    		}
    	}
        //01背包
    	for (int i=1;i<=n;i++){
    		if (w[i]==0&&v[i]==0)continue;
    		for (int j=maxn;j>=w[i];j--)dq[j]=max(dq[j],dq[j-w[i]]+v[i]);
    	}
    	cout<<dq[maxn];//输出
    	return 0;
    }//AC
    
    • 1

    信息

    ID
    924
    时间
    1000ms
    内存
    128MiB
    难度
    8
    标签
    递交数
    11
    已通过
    9
    上传者