• topcoder srm 630 div1 (2-SAT and SCC template)


    problem1 link

    首先计算任意两点的距离。然后枚举选出的集合中的两个点,判断其他点是否可以即可。

    problem2 link

    假设字符串为$s$,长度为$n$。那么对于$SA$中的两个排名$SA_{i},SA_{i+1}$来说,应该尽量使得$s[SA_{i}]=s[SA_{i+1}]$。如果这个满足的话,那么需要两个后缀满足$s[SA_{i}+1sim n-1]<s[SA_{i+1}+1sim n-1]$,设他们的排名分别为$SA_{r},SA_{k}$,也就是说$r<k$即可。

    problem3 link

     这个可以转化为2-SAT问题。

    首先将每个点拆成202个点,分别表示$leq 0,leq 1,...,leq 100,>0,>1,...,>100$.然后就是每一个等式可以转化为一些2-SAT中的限制。

    比如对于$g_{x}+g_{y}<50$来说.比如$g_{x}> 19,g_{y}> 29$是冲突的,那么在2-SAT可以描述为$g_{x}> 19 ightarrow g_{y}leq  29$,以及$g_{y}> 29 ightarrow g_{x}leq  19$

    最后就是得到2_SAT的一组解。

    code for problem1

    #include <algorithm>
    #include <unordered_set>
    #include <vector>
    
    class Egalitarianism3 {
     public:
      int maxCities(int n, const std::vector<int> &a, const std::vector<int> &b,
                    const std::vector<int> &len) {
        if (n == 1) {
          return 1;
        }
        std::vector<std::vector<int>> g(n, std::vector<int>(n, -1));
        for (int i = 0; i < n - 1; ++i) {
          g[a[i] - 1][b[i] - 1] = g[b[i] - 1][a[i] - 1] = len[i];
        }
        for (int i = 0; i < n; ++i) {
          g[i][i] = 0;
        }
        for (int i = 0; i < n; ++i) {
          for (int u = 0; u < n; ++u) {
            if (g[u][i] != -1) {
              for (int v = 0; v < n; ++v) {
                if (g[i][v] != -1) {
                  if (g[u][v] == -1 || g[u][v] > g[u][i] + g[i][v]) {
                    g[u][v] = g[u][i] + g[i][v];
                  }
                }
              }
            }
          }
        }
        auto Compute = [&](int s, int t) {
          std::unordered_set<int> all;
          all.insert(s);
          all.insert(t);
          const int d = g[s][t];
          for (int i = 0; i < n; ++i) {
            if (all.find(i) == all.end()) {
              bool tag = true;
              for (auto e : all) {
                if (g[i][e] != d) {
                  tag = false;
                  break;
                }
              }
              if (tag) {
                all.insert(i);
              }
            }
          }
          return static_cast<int>(all.size());
        };
        int result = 0;
        for (int i = 0; i < n; ++i) {
          for (int j = i + 1; j < n; ++j) {
            result = std::max(result, Compute(i, j));
          }
        }
        return result;
      }
    };

    code for problem2

    #include <vector>
    
    class SuffixArrayDiv1 {
     public:
      int minimalCharacters(const std::vector<int> &SA) {
        int n = static_cast<int>(SA.size());
        std::vector<int> s(n + 1, -1);
        for (int i = 0; i < n; ++i) {
          s[SA[i]] = i;
        }
        int result = 1;
        for (int i = 0; i + 1 < n; ++i) {
          if (s[SA[i] + 1] > s[SA[i + 1] + 1]) {
            ++result;
          }
        }
        return result;
      }
    };

    code for problem3

    #include <algorithm>
    #include <stack>
    #include <unordered_map>
    #include <unordered_set>
    #include <vector>
    
    class StronglyConnectedComponentSolver {
     public:
      StronglyConnectedComponentSolver() = default;
    
      void Initialize(int n) { edges_.resize(n); }
    
      std::vector<int> Solve() {
        total_ = static_cast<int>(edges_.size());
        if (total_ == 0) {
          return {};
        }
        visited_.resize(total_, false);
        low_indices_.resize(total_, 0);
        dfs_indices_.resize(total_, 0);
        connected_component_indices_.resize(total_, 0);
        for (int i = 0; i < total_; ++i) {
          if (0 == dfs_indices_[i]) {
            Dfs(i);
          }
        }
        return connected_component_indices_;
      }
    
      int VertexNumber() const { return static_cast<int>(edges_.size()); }
    
      inline void AddEdge(int from, int to) { edges_[from].push_back(to); }
    
      const std::vector<int> &Tos(int u) const { return edges_[u]; }
    
     private:
      void Dfs(const int u) {
        low_indices_[u] = dfs_indices_[u] = ++index_;
        stack_.push(u);
        visited_[u] = true;
        for (auto v : edges_[u]) {
          if (0 == dfs_indices_[v]) {
            Dfs(v);
            low_indices_[u] = std::min(low_indices_[u], low_indices_[v]);
          } else if (visited_[v]) {
            low_indices_[u] = std::min(low_indices_[u], dfs_indices_[v]);
          }
        }
        if (dfs_indices_[u] == low_indices_[u]) {
          int v = 0;
          do {
            v = stack_.top();
            stack_.pop();
            visited_[v] = false;
            connected_component_indices_[v] = connected_component_index_;
          } while (u != v);
          ++connected_component_index_;
        }
      }
    
      std::vector<std::vector<int>> edges_;
      int total_ = 0;
      std::vector<bool> visited_;
      std::vector<int> low_indices_;
      std::vector<int> dfs_indices_;
      std::stack<int> stack_;
      int index_ = 0;
      int connected_component_index_ = 0;
      std::vector<int> connected_component_indices_;
    };
    
    class TwoSatisfiabilitySolver {
     public:
      void Initialize(int total_vertex_number) {
        scc_solver_.Initialize(total_vertex_number);
      }
    
      // If idx1 is type1, then idx2 must be type2.
      void AddConstraint(int idx1, bool type1, int idx2, bool type2) {
        int from = idx1 * 2 + (type1 ? 1 : 0);
        int to = idx2 * 2 + (type2 ? 1 : 0);
        scc_solver_.AddEdge(from, to);
      }
    
      void AddConflict(int idx1, bool type1, int idx2, bool type2) {
        AddConstraint(idx1, type1, idx2, !type2);
        AddConstraint(idx2, type2, idx1, !type1);
      }
    
      void AddLead(int idx1, bool type1, int idx2, bool type2) {
        AddConstraint(idx1, type1, idx2, type2);
        AddConstraint(idx2, !type2, idx1, !type1);
      }
    
      // The idx must not be type
      void SetFalse(int idx, bool type) { SetTrue(idx, !type); }
    
      // The idx must be type
      void SetTrue(int idx, bool type) { AddConstraint(idx, !type, idx, type); }
    
      bool ExistSolution() {
        if (scc_indices_.empty()) {
          scc_indices_ = scc_solver_.Solve();
          total_scc_number_ =
              *std::max_element(scc_indices_.begin(), scc_indices_.end()) + 1;
        }
        for (int i = 0; i < scc_solver_.VertexNumber() / 2; ++i) {
          if (scc_indices_[i * 2] == scc_indices_[i * 2 + 1]) {
            return false;
          }
        }
        return true;
      }
    
      std::vector<bool> GetOneSolution() {
        if (!ExistSolution()) {
          return {};
        }
        BuildNewGraph();
        TopSort();
        int total = scc_solver_.VertexNumber();
        std::vector<bool> result(total / 2);
        for (int e = 0; e < total / 2; ++e) {
          if (last_color_[scc_indices_[e * 2]] == 0) {
            result[e] = false;
          } else {
            result[e] = true;
          }
        }
        return std::move(result);
      }
    
     private:
      void BuildNewGraph() {
        new_edges_.resize(total_scc_number_);
        new_graph_node_in_degree_.resize(total_scc_number_, 0);
        int total = scc_solver_.VertexNumber();
        for (int i = 0; i < total; ++i) {
          int scc0 = scc_indices_[i];
          for (auto e : scc_solver_.Tos(i)) {
            int scc1 = scc_indices_[e];
            if (scc0 != scc1 &&
                new_edges_[scc1].find(scc0) == new_edges_[scc1].end()) {
              new_edges_[scc1].insert(scc0);
              ++new_graph_node_in_degree_[scc0];
            }
          }
        }
      }
    
      void TopSort() {
        std::vector<int> conflict(total_scc_number_);
        int total = scc_solver_.VertexNumber() / 2;
        for (int i = 0; i < total; ++i) {
          conflict[scc_indices_[i * 2]] = scc_indices_[i * 2 + 1];
          conflict[scc_indices_[i * 2 + 1]] = scc_indices_[i * 2];
        }
        last_color_.resize(total_scc_number_, -1);
        std::stack<int> st;
        for (int i = 0; i < total_scc_number_; ++i) {
          if (0 == new_graph_node_in_degree_[i]) {
            st.push(i);
          }
        }
        while (!st.empty()) {
          int u = st.top();
          st.pop();
          if (last_color_[u] == -1) {
            last_color_[u] = 0;
            last_color_[conflict[u]] = 1;
          }
          for (auto e : new_edges_[u]) {
            int cur = --new_graph_node_in_degree_[e];
            if (cur == 0) {
              st.push(e);
            }
          }
        }
      }
    
      std::vector<int> scc_indices_;
      int total_scc_number_ = 0;
      std::vector<std::unordered_set<int>> new_edges_;
      std::vector<int> new_graph_node_in_degree_;
      std::vector<int> last_color_;
    
      StronglyConnectedComponentSolver scc_solver_;
    };
    
    class NeverAskHerAge {
     public:
      std::vector<int> possibleSolution(int n, const std::vector<int> &id1,
                                        const std::vector<int> &id2,
                                        const std::vector<std::string> &op,
                                        const std::vector<std::string> &rl,
                                        const std::vector<int> &val) {
        solver.Initialize(n * 101 * 2);
        int m = static_cast<int>(id1.size());
        // 0: <= j
        // 1: > j
        for (int i = 1; i <= n; ++i) {
          for (int j = 0; j <= 100; ++j) {
            if (j > 0) {
              solver.AddLead(GetIndex(i, j), 1, GetIndex(i, j - 1), 1);
            }
            if (j + 1 < 100) {
              solver.AddLead(GetIndex(i, j), 0, GetIndex(i, j + 1), 0);
            }
          }
          solver.SetFalse(GetIndex(i, 0), 0);
          solver.SetFalse(GetIndex(i, 100), 1);
        }
        for (int i = 0; i < m; ++i) {
          if (rl[i] == "=") {
            Add(id1[i], id2[i], op[i][0], ">=", val[i]);
            Add(id1[i], id2[i], op[i][0], "<=", val[i]);
          } else {
            Add(id1[i], id2[i], op[i][0], rl[i], val[i]);
          }
        }
        if (!solver.ExistSolution()) {
          return {};
        }
        std::vector<int> result(n);
        auto sol = solver.GetOneSolution();
        for (int i = 0; i < n; ++i) {
          for (int j = 1; j < 101; ++j) {
            int t = GetIndex(i + 1, j);
            if (!sol[t]) {
              result[i] = j;
              break;
            }
          }
        }
        return result;
      }
    
     private:
      void Add(int x, int y, char op, const std::string &rl, int z) {
        if (op == '+' || op == '*') {
          if (rl[0] == '<') {
            AddMulLess(x, y, op, rl, z);
          } else {
            AddMulGreater(x, y, op, rl, z);
          }
        } else {
          if (rl[0] == '<') {
            SubDivLess(x, y, op, rl, z);
          } else {
            SubDivGreater(x, y, op, rl, z);
          }
        }
      }
    
      void AddMulLess(int g1, int g2, char op, const std::string &rl, int z) {
        // Assume g2 > i - 1, (i, i+1, i+2, ..., 100)
        for (int i = 1; i <= 101; ++i) {
          // If rl is '<', then 1000(i + j) < z.
          //    Here consider opposite: 1000(i + j) >= z.
          //    Get j >= ceil((z - 1000i) / 1000) = (z - 1000i + 999) / 1000
          //    So g2 >= i and g1 >= j conflicts
          // If rl is '<=', then 1000(i + j) <= z.
          //    Here consider opposite: 1000(i + j) > z.
          //    Get j >= floor((z - 1000i) / 1000) + 1 = (z - 1000i + 1000) / 1000
          //    So g2 >= i and g1 >= j conflicts
          int j = op == '+' ? Ceil(z - 1000 * i, 1000, EqualTag(rl))
                            : Ceil(z, i * 1000, EqualTag(rl));
          if (j < 1) {
            solver.SetFalse(GetIndex(g2, i - 1), 1);
          } else if (j <= 101) {
            solver.AddConflict(GetIndex(g2, i - 1), 1, GetIndex(g1, j - 1), 1);
          }
        }
      }
    
      void AddMulGreater(int g1, int g2, char op, const std::string &rl, int z) {
        for (int i = 0; i < 101; ++i) {
          int j = op == '+' ? Floor(z - 1000 * i, 1000, EqualTag(rl))
                            : Floor(z, i * 1000, EqualTag(rl));
          if (j >= 101) {
            solver.SetFalse(GetIndex(g2, i), 0);
          } else if (j >= 0) {
            solver.AddConflict(GetIndex(g2, i), 0, GetIndex(g1, j), 0);
          }
        }
      }
    
      void SubDivGreater(int g1, int g2, char op, const std::string &rl, int z) {
        for (int i = 1; i <= 101; ++i) {
          int j = op == '-' ? Floor(z + 1000 * i, 1000, EqualTag(rl))
                            : Floor(z * i, 1000, EqualTag(rl));
          if (j >= 101) {
            solver.SetFalse(GetIndex(g2, i - 1), 1);
          } else if (j >= 0) {
            solver.AddConflict(GetIndex(g2, i - 1), 1, GetIndex(g1, j), 0);
          }
        }
      }
    
      void SubDivLess(int g1, int g2, char op, const std::string &rl, int z) {
        for (int i = 0; i < 101; ++i) {
          int j = op == '-' ? Ceil(z + 1000 * i, 1000, EqualTag(rl))
                            : Ceil(z * i, 1000, EqualTag(rl));
          if (j < 1) {
            solver.SetFalse(GetIndex(g2, i), 0);
          } else if (j <= 101) {
            solver.AddConflict(GetIndex(g2, i), 0, GetIndex(g1, j - 1), 1);
          }
        }
      }
    
      bool EqualTag(const std::string &rl) { return rl.length() < 2; }
    
      int Ceil(int x, int y, bool tag) {
        if (x < 0) {
          return -1;
        }
        return (x + y - (tag ? 1 : 0)) / y;
      }
    
      int Floor(int x, int y, bool tag) {
        if (y == 0) {
          return 101;
        }
        if (x <= 0) {
          return -1;
        }
        return (x - (tag ? 0 : 1)) / y;
      }
    
      int GetIndex(int i, int j) { return (i - 1) * 101 + j; }
    
      TwoSatisfiabilitySolver solver;
    };
  • 相关阅读:
    JS定时器做物体运动
    JS做动态表格
    JS如何做2048(详细)
    改变 C/C++ 控制台程序的输出颜色和样式
    The Game Of Life – 数据结构与算法的敲门砖
    适用于 macOS 下 2K 显示器开启 HiDPI 的简便解决方案
    「踩坑记」Android API 判断权限申请结果的闪退问题
    Hello World!
    js 放大镜效果
    js 随机验证码生成及校验
  • 原文地址:https://www.cnblogs.com/jianglangcaijin/p/9973151.html
Copyright © 2020-2023  润新知