并查集
例题:格子游戏
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 40010;
int p[N];
int n,m;
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int get(int x,int y)
{
return x*n+y;
}
int main()
{
cin >> n >> m;
int res;
for(int i=0;i<n*n;i++) p[i]=i;
for(int i=1;i<=m;i++){
int x,y;
int a,b;
char op;
cin >> x >> y >> op;
x--,y--;
a=get(x,y);
if(op=='D') b=get(x+1,y);
else b=get(x,y+1);
int pa=find(a),pb=find(b);
if(pa==pb){
res=i;
break;
}
p[pa]=pb;
}
if(!res) puts("draw");
else cout << res << endl;
return 0;
}
思路:
图上的每个点都会对应一个二维坐标,我们将其转化为一维坐标方便计算和操作,转化公式见 g e t get get 函数,将画的边的起点和终点坐标分别表示出来,找各自的父节点,如果他们的父节点相同表示连通了,(如果不连通记得将这两个点合并为一个集合)即围成圈了。
例题:搭配购买
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 10010;
int n,m,vol;
int p[N],v[N],w[N];
int f[N];
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
cin >> n >> m >> vol;
for(int i=1;i<=n;i++) cin >> v[i] >> w[i];
for(int i=1;i<=n;i++) p[i]=i;
while(m--)
{
int a,b;
cin >> a >> b;
int pa=find(a),pb=find(b);
if(pa!=pb)
{
p[pa]=pb;
v[pb]+=v[pa];
w[pb]+=w[pa];
}
}
for(int i=1;i<=n;i++)//枚举物品
{
if(p[i]==i)//如果是根节点
{
for(int j=vol;j>=v[i];j--)//枚举价钱(体积)
{
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
}
}
cout << f[vol] << endl;
return 0;
}
例题:程序自动分析
有🕳!
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
const int N = 2e6+10;
int p[N];
int cnt;
unordered_map<int,int>mp;
struct node{
int x,y,e;
}query[N];
int get(int x)
{
if(!mp.count(x)) mp[x]=++cnt;
return mp[x];
}
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
int t; cin >> t ;
while(t--)
{
cnt=0;
mp.clear();
int n; cin>> n;
for(int i=1;i<=n;i++) p[i]=i;//这里初始化要两倍的n呢QAQ
for(int i=1;i<=n;i++){
int x,y,e;
cin >> x >> y >> e;
query[i]={get(x),get(y),e};
}
for(int i=1;i<=n;i++)
{
if(query[i].e==1){
int pi=find(query[i].x),pj=find(query[i].y);
p[pi]=pj;
}
}
bool has_conflict=0;
for(int i=1;i<=n;i++)
{
if(query[i].e==0){
int pa=find(query[i].x),pb=find(query[i].y);
if(pa==pb) {
has_conflict=1;
break;
}
}
}
if(has_conflict) puts("NO");
else puts("YES");
}
return 0;
}
并查集+ 01 01 01背包
把需要搭配购买的放到一个集合,然后对所有集合进行 01 01 01背包
例题:银河英雄传说
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 3e4+10;
int p[N],d[N],Size[N];
int find(int x)
{
if(p[x]!=x){
int root = find(p[x]);
d[x]+=d[p[x]];
p[x]=root;
}
return p[x];
}
int main()
{
int t; cin >> t;
for(int i=0;i<N;i++) {
p[i]=i;
Size[i]=1;
}
while(t--)
{
char op;
int a,b;
cin >> op >> a >> b;
int pa=find(a),pb=find(b);
if(op=='M'){
p[pa]=pb;
d[pa]=Size[pb];
Size[pb]+=Size[pa];
}
else {
if(pa!=pb) puts("-1");
else cout << max(0, abs(d[a] - d[b]) - 1) << endl;
}
}
return 0;
}