1 条题解
-
0
乍一看是背包,细看...
哎呦!!并查集
背包都懂吧(不懂都别看了)
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
- 上传者