并查集_数据结构作业

博客主要讲述了博主做并查集相关题目的经历,包括从51nod上扒的题,在路径压缩时遇到困难,对一些题用set的做法表示不解,还提到正常模板题及逆向并查集,最后给出输入输出样例并表示思考更简单思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

7-1挂皮筋
zcx在51nod1307上扒的题
路径压缩把我压自闭了
结果rm不用优化就直接过???我服

#include<bits/stdc++.h>
#define Maxn 50000
using namespace std;
int fa[Maxn], r[Maxn];
bool flag = true;
void Init(int n){
    for(int i = 0; i < n; i++) fa[i] = i;
}
void Find(int x, int w){
 int f;
    if(fa[x] != x){
        int pre = fa[x];
        Find(fa[x], w);
        r[x] = min(r[pre], r[x] - w);
    }
    else r[x] -= w;
    if(r[x] < 0) flag = false;
}
int main(){
    int n, c, w, p, i;
    cin >> n;
    Init(n);
    for(i = 0; i < n; i++){
        cin >> c >> w >> p;
        if(p == -1){
            r[i] = c - w;
            if(r[i] < 0) break;
        }
        else{
         fa[i] = p;
         r[i] = c;
            Find(i, w);
            if(!flag) break;
        }
    }
    cout << i << endl;
    return 0;
}

7-2
还是zcx在51nod1515上扒的题
我也不明白好好地并查集她为啥子要搞set
害得老子想压缩路径想到头秃
嘻m嘻m嘻p
搜到的题解都写得好jb长
真不明白明明50行就可以解决的问题为啥子非要写一百行

#include<bits/stdc++.h>
using namespace std;
static const int MAXN = 2e5 + 5;
int fa[MAXN], n, num;
map <int, int> table;
set<int> dif[MAXN];
void Init(){
 for(int i = 0; i <= 2 * n; ++i) fa[i] = i;
}
int Find(int x){
 return x == fa[x] ? x : fa[x] = Find(fa[x]);
}
int main(){
 int x, y, p;
 scanf("%d", &n);
 Init();
 while(n--){
  scanf("%d%d%d", &x, &y, &p);
  map<int, int>::iterator it = table.find(x);
  x = (it == table.end()) ? (table[x] = num++) : table[x];
  it = table.find(y);
  y = (it == table.end()) ? (table[y] = num++) : table[y]; 
  x = Find(x), y = Find(y);
  if(p == 1){
   if(x == y) puts("YES");
   else{
    set<int>::iterator it = dif[x].find(y);
    if(it == dif[x].end()){
     puts("YES");
     if(dif[x].size() > dif[y].size()) swap(x, y);
     fa[x] = y;
     for(it = dif[x].begin(); it != dif[x].end(); it++){
      dif[*it].insert(y);
      dif[y].insert(*it);
     }
    }
    else puts("NO");  
   }
  }
  else if(p == 0){
   if(x == y) puts("NO");
   else{
    puts("YES");
    dif[x].insert(y);
    dif[y].insert(x); 
   }
  }
 }
 return 0;
}

7-3终于正常模板题了 感动
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
int fa[10005];
void Init(int n){
    for(int i = 1; i <= n; i++) fa[i] = i;
}
int Find(int x){
    return (x == fa[x]) ? x : fa[x] = Find(fa[x]);
}
int main() {
    int n, q, opt, u, v;
    scanf("%d%d", &n, &q);
 Init(n);
    while(q--){
        scanf("%d%d%d", &opt, &u, &v);
  int fu = Find(u), fv = Find(v);
        if(opt == 1 && fu != fv) fa[fu] = fv;
        else if(opt == 2) printf(fu == fv ? "Y\n" : "N\n");
    }
    return 0;
}

7-4
逆向并查集
在这里插入图片描述
输入样例:
8 13
0 1
1 6
6 5
5 0
0 6
1 2
2 3
3 4
4 5
7 1
7 2
7 6
3 6
5
1
6
3
5
7
输出样例:
1
1
1
2
3

#include<bits/stdc++.h>
using namespace std;
static const int INF = 1e9;
typedef pair<int, int> P;
P p[200010];
int vis[400010], fa[400010], n, m, k, cnt;
vector <int> q[400010];
vector <int> ans;
stack <int> S;
void Init(){
 cnt = n - k;
 for(int i = 0; i < n; i++){vis[i] = INF; fa[i] = i;} 
 while(!S.empty()) S.pop();
}
int Find(int x){
 return (fa[x] == x) ? fa[x] : fa[x] = Find(fa[x]);
}
void merge(int x, int y){
 int fx = Find(x), fy = Find(y);
 if(fx != fy){fa[fx] = fy;cnt--;}
}
void print(){
 for(int i = k; i >= 0; i--) printf("%d\n", ans[i]);
}
int main(){
 int x, y;
 scanf("%d%d", &n ,&m); 
 for(int i = 0; i < m; i++){
  scanf("%d%d", &x, &y);
  p[i].first = x; p[i].second = y;
 }
 scanf("%d", &k);
 Init();
 for(int i = 1; i <= k; i++){
  scanf("%d", &x);
  S.push(x);
  vis[x] = i;
 }
 for(int i = 0; i < m ;i++){
  x = p[i].first, y = p[i].second;
  if(vis[x] < vis[y]) q[x].push_back(y);
  else if(vis[y] < vis[x]) q[y].push_back(x);
  else merge(x, y);
 }
 ans.push_back(cnt);
 while(!S.empty()){
  int u = S.top(); S.pop();
  for(int i = 0; i < q[u].size(); i++) merge(u, q[u][i]);
  ans.push_back(++cnt);
 }
 print();
 return 0;
}

感觉我做得稍显麻烦 不知道有没有更简单的思路……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值