Stay Hungry,Stay Foolish!

D - Good Tuple Problem atcoder abc 327

D - Good Tuple Problem

https://atcoder.jp/contests/abc327/tasks/abc327_d

 

思路 - dfs染色判断

https://www.zhihu.com/question/292465499

判断二分图

的常见方法是染色法:用两种颜色,对所有顶点逐个染色,且相邻顶点染不同的颜色

如果发现相邻顶点染了同一种颜色,就认为此图不为二分图

当所有顶点都被染色,且没有发现同色的相邻顶点,就退出

 

Code - dfs染色判断

https://atcoder.jp/contests/abc327/submissions/47406923

#include<cstdio>
#include<iostream>
#include<vector>

using namespace std;
int n,m,color[200010], a[200010], b[200010];
vector<int> edge[200010];


int dfs(int x,int c){
    color[x]=c

;
    for(int i=0;i<edge[x].size();i++){
        int v=edge[x][i];
        if(color[v]==color[x]){
            return 0;
        }
        if(color[v]==0 && !dfs(v,-c)){
            return 0;
        }
    }
    return 1;
}
void solve(){
    for(int i=1;i<=n;i++){
        if(color[i]==0){
            if(!dfs(i,1)){
                printf("No");
                return ;
            }
        }
    }
    printf("Yes");
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        cin >> a[i];
    }
    
    for(int i=1;i<=m;i++){
        cin >> b[i];
    }

    for(int i=1;i<=m;i++){
        int x,y;
        x = a[i];
        y = b[i];
//        scanf("%d%d",&x,&y);
        edge[x].push_back(y);
        edge[y].push_back(x);
    }
    solve();
    return 0;
}

 

思路 -- 并查集

https://www.cnblogs.com/Jojo-L/p/16520445.html

如果图是二分图的话,那么图中每个顶点的所有邻接点都应该属于同一集合,且不与顶点处于同一集合。因此可以使用并查集来解决这个问题:

遍历图中每个顶点,将当前顶点的所有邻接点进行合并,并判断这些邻接点中是否存在某一邻接点已经和当前顶点处于同一个集合中,若是,则说明不是二分图。

 https://zhuanlan.zhihu.com/p/161082172

遍历图中每个顶点:

    将当前顶点的所有邻接点进行合并判断是否存在邻接点与当前顶点已经在一个集合中了,若存在,则说明不是二分图

 

Code

/**
 *    author:  tourist
 *    created: 10.07.2022 18:40:44
**/
#include <bits/stdc++.h>

using namespace std;

#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif

class dsu {
 public:
  vector<int> p;
  int n;

  dsu(int _n) : n(_n) {
    p.resize(n);
    iota(p.begin(), p.end(), 0);
  }

  inline int get(int x) {
    return (x == p[x] ? x : (p[x] = get(p[x])));
  }

  inline bool unite(int x, int y) {
    x = get(x);
    y = get(y);
    if (x != y) {
      p[x] = y;
      return true;
    }
    return false;
  }
  
  inline bool is_connected(int x, int y){
    x = get(x);
    y = get(y);
    if (x == y) {
      return true;
    }
    
    return false;
  }
};

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int tt = 1;

  while (tt--) {
    int n, m;
    cin >> n >> m;

    dsu d(n);

    vector<int> a(m);
    vector<int> b(m);

    for (int i = 0; i < m; i++) {
      cin >> a[i];
    }

    for (int i = 0; i < m; i++) {
      cin >> b[i];
    }

    vector<vector<int>> mp(n);

    for (int i = 0; i < m; i++) {
          int x = a[i];
          int y = b[i];

        x--;
        y--;

        mp[x].push_back(y);
        mp[y].push_back(x);
    }

    for (int i = 0; i < n; i++) {
        if (mp[i].size() == 0){
            continue;
        }
        
        int first_neighbor = *mp[i].begin();
        
        for(auto next : mp[i]){
            if (d.is_connected(i, next)){
                cout << "No" << endl;
                return 0;
            }
            
            d.unite(first_neighbor, next);
        }
    }

    cout << "Yes" << '\n';
  }

  return 0;
}

 

 

思路 -- 扩展域并查集

https://www.cnblogs.com/zsh-notes/p/12820467.html

把每个节点扩展为两个节点(一正一反),若a与b不能在一起(在同一个集合),则把a的正节点与b的反节点放一起,把b的正节点与a的反节点放一起,这样就解决了a与b的冲突。若发现a的正节点与b的正节点已经在一起,那么说明之前的某对关系与(a,b)这对关系冲突,不可能同时满足,即不能成功完成整个操作。

https://www.cnblogs.com/yHan234/p/16473336.html

 

https://www.zhihu.com/question/474576285

证明:假设二分图中的环是奇数环。

 

设一个环,x1,x2,x3,,,,x(2*k-1),k>=1且为整数。相邻两点有边连接,x1与x(2*k-1)相连。

 

由二分图定义可知:x1与x2分别在X集合和Y集合,由于x2与x3的关系可知x3在X集合,则x4在Y集合,以此类推,可得奇数点在X集合,偶数点在Y集合,那么点x(2*k-1)则在X集合中,即与x1同为一个集合,但有之间假设的x1与x(2*k-1)有连边,那么此时就与二分图定义不符,这二分图中的环不可能是奇数环。

 

Code -- 扩展域并查集

https://atcoder.jp/contests/abc327/submissions/47434599

/**
 *    author:  tourist
 *    created: 10.07.2022 18:40:44
**/
#include <bits/stdc++.h>

using namespace std;

#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif

class dsu {
 public:
  vector<int> p;
  int n;

  dsu(int _n) : n(_n) {
    p.resize(n);
    iota(p.begin(), p.end(), 0);
  }

  inline int get(int x) {
    return (x == p[x] ? x : (p[x] = get(p[x])));
  }

  inline bool unite(int x, int y) {
    x = get(x);
    y = get(y);
    if (x != y) {
      p[x] = y;
      return true;
    }
    return false;
  }
};

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int tt = 1;
//  cin >> tt;
  while (tt--) {
    int n, m;
    cin >> n >> m;
    vector<int> deg(n);
    
    dsu d(2 * n);
    
    vector<int> a(m);
    vector<int> b(m);
    
    for (int i = 0; i < m; i++) {
      cin >> a[i];
      }

    for (int i = 0; i < m; i++) {
      cin >> b[i];
      }

    for (int i = 0; i < m; i++) {
      int x = a[i];
      int y = b[i];
      
      x--;
      y--;
      
      deg[x] += 1;
      deg[y] += 1;
      
      d.unite(x, y + n);
      d.unite(x + n, y);
    }
    
    bool ok = true;
    for (int i = 0; i < n; i++) {
//      if (deg[i] > 2) {
//        ok = false;
//      }
      
      if (d.get(i) == d.get(i + n)) {
        ok = false;
      }
    }
    
    cout << (ok ? "Yes" : "No") << '\n';
  }
  
  return 0;
}

 

posted @ 2023-11-10 09:34  lightsong  阅读(26)  评论(1编辑  收藏  举报
Life Is Short, We Need Ship To Travel