topcoder srm 590 div1 [FINISHED](模拟, 高斯消元,最小割)

problem1 link

对于每一个,找到其在目标串中的位置,判断能不能移动即可。

problem2 link

如果最后的$limit$为$11=(1011)_{2}$,那么可以分别计算值为$(1011)_{2},(1010)_{2},(100x)_{2},(0xxx)_{2}$的答案数,$x$位置表示可以为任意。也就是可以忽略这些位。

当答案固定时,可以用高斯消元求解。

problem3 link

令$d(i,j)$表示点 $i$到点$j$的距离。

使用最小割求解。将每个点拆成$n$个点,第$i$个点拆成$p(i,0),p(i,1),...,p(i,n-1)$.其中$p(i,j)$如果与源点在一个割集,说明$d(0,i)\leq j$为假,与汇点在一个割集说明$d(0,i)\leq j$为真。

所以,如果一个割产生在边$p(i,j-1)\rightarrow p(i,j)$说明最后$d(0,i)=j$.其中边$p(i,j-1)\rightarrow p(i,j)$的代价为$(want[i]-j)^{2}$

有以下边:

  (1) 对于0点来说,$p(0,0)$与汇点的边流量为无穷大,说明,最后它与汇点在一个割集,所以$d(0,0)\leq 0$为真;

  (2) 对于$1\leq i < n$号点来说,源点到$p(i,0)$为无穷大(一定不可能),$p(i, n-1)$到汇点为无穷大(一定为真); $p(i,j-1)\rightarrow p(i,j),1\leq j < n)$为$(want[i]-j)^{2}$

  (3) 如果原来存在边$i\rightarrow j$,那么$p(i,k)\rightarrow p(j,k-1)$为无穷大,表示如果$d(0,i)>k$,那么一定有$d(0,j)>k-1$

 

code for problem1

#include <string>

class FoxAndChess {
 public:
  std::string ableToMove(const std::string &begin, const std::string &target) {
    int n = static_cast<int>(begin.size());
    int idx = 0;
    for (int i = 0; i < n; ++i) {
      if (begin[i] == 'L' || begin[i] == 'R') {
        while (idx < n && target[idx] == '.') {
          ++idx;
        }
        if (idx == n || begin[i] != target[idx] ||
            (begin[i] == 'L' && i < idx) || (begin[i] == 'R' && i > idx)) {
          return "Impossible";
        }
        ++idx;
      }
    }
    while (idx < n && target[idx] == '.') {
      ++idx;
    }
    if (idx != n) {
      return "Impossible";
    }
    return "Possible";
  }
};

code for problem2

#include <vector>

class XorCards {
 public:
  long long numberOfWays(const std::vector<long long> &number,
                         long long limit) {
    const int n = 52;
    const int m = static_cast<int>(number.size());
    long long result = 0;
    auto GetBit = [](long long t, int b) -> int {
      return (t & (1ll << b)) != 0 ? 1 : 0;
    };
    {
      std::vector<std::vector<int>> g(n, std::vector<int>(m + 1, 0));
      for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
          g[i][j] = GetBit(number[j], i);
        }
        g[i][m] = GetBit(limit, i);
      }
      result += Gauss(g);
    }
    for (int i = 0; i < n; ++i) {
      if (GetBit(limit, i) == 0) {
        continue;
      }
      std::vector<std::vector<int>> g(n, std::vector<int>(m + 1, 0));
      for (int j = i; j < n; ++j) {
        for (int k = 0; k < m; ++k) {
          g[j][k] = GetBit(number[k], j);
        }
        if (j > i) {
          g[j][m] = GetBit(limit, j);
        }
      }
      result += Gauss(g);
    }
    return result;
  }

 private:
  long long Gauss(std::vector<std::vector<int>> &g) {
    int n = static_cast<int>(g.size());
    int m = static_cast<int>(g[0].size()) - 1;
    int col = 0;

    auto HasBit = [&](int start, int col) {
      for (int i = n - 1; i >= start; --i) {
        if (g[i][col] != 0) return i;
      }
      return -1;
    };
    int row_number = 0;
    for (int i = 0; i < n && col < m; ++i) {
      int row = HasBit(i, col);
      while (row == -1 && col + 1 < m) {
        row = HasBit(i, ++col);
      }
      if (row == -1) {
        break;
      }
      if (row != i) {
        std::swap(g[i], g[row]);
      }
      for (int idx = 0; idx < n; ++idx) {
        if (idx != i && g[idx][col] != 0) {
          for (int k = 0; k <= m; ++k) {
            g[idx][k] ^= g[i][k];
          }
        }
      }
      ++col;
      ++row_number;
    }
    for (int i = row_number; i < n; ++i) {
      if (g[i][m] != 0) {
        return 0;
      }
    }
    if (m < row_number) {
      return 0;
    }
    return 1ll << (m - row_number);
  }
};

code for problem3

#include <limits>
#include <unordered_map>
#include <vector>

template <typename FlowType>
class MaxFlowSolver {
  static constexpr FlowType kMaxFlow = std::numeric_limits<FlowType>::max();
  static constexpr FlowType kZeroFlow = static_cast<FlowType>(0);
  struct node {
    int v;
    int next;
    FlowType cap;
  };

 public:
  int VertexNumber() const { return used_index_; }

  FlowType MaxFlow(int source, int sink) {
    source = GetIndex(source);
    sink = GetIndex(sink);

    int n = VertexNumber();
    std::vector<int> pre(n);
    std::vector<int> cur(n);
    std::vector<int> num(n);
    std::vector<int> h(n);
    for (int i = 0; i < n; ++i) {
      cur[i] = head_[i];
      num[i] = 0;
      h[i] = 0;
    }
    int u = source;
    FlowType result = 0;
    while (h[u] < n) {
      if (u == sink) {
        FlowType min_cap = kMaxFlow;
        int v = -1;
        for (int i = source; i != sink; i = edges_[cur[i]].v) {
          int k = cur[i];
          if (edges_[k].cap < min_cap) {
            min_cap = edges_[k].cap;
            v = i;
          }
        }
        result += min_cap;
        u = v;
        for (int i = source; i != sink; i = edges_[cur[i]].v) {
          int k = cur[i];
          edges_[k].cap -= min_cap;
          edges_[k ^ 1].cap += min_cap;
        }
      }
      int index = -1;
      for (int i = cur[u]; i != -1; i = edges_[i].next) {
        if (edges_[i].cap > 0 && h[u] == h[edges_[i].v] + 1) {
          index = i;
          break;
        }
      }
      if (index != -1) {
        cur[u] = index;
        pre[edges_[index].v] = u;
        u = edges_[index].v;
      } else {
        if (--num[h[u]] == 0) {
          break;
        }
        int k = n;
        cur[u] = head_[u];
        for (int i = head_[u]; i != -1; i = edges_[i].next) {
          if (edges_[i].cap > 0 && h[edges_[i].v] < k) {
            k = h[edges_[i].v];
          }
        }
        if (k + 1 < n) {
          num[k + 1] += 1;
        }
        h[u] = k + 1;
        if (u != source) {
          u = pre[u];
        }
      }
    }
    return result;
  }

  MaxFlowSolver() = default;

  void Clear() {
    edges_.clear();
    head_.clear();
    vertex_indexer_.clear();
    used_index_ = 0;
  }

  void InsertEdge(int from, int to, FlowType cap) {
    from = GetIndex(from);
    to = GetIndex(to);
    AddEdge(from, to, cap);
    AddEdge(to, from, kZeroFlow);
  }

 private:
  int GetIndex(int idx) {
    auto iter = vertex_indexer_.find(idx);
    if (iter != vertex_indexer_.end()) {
      return iter->second;
    }
    int map_idx = used_index_++;
    head_.push_back(-1);
    return vertex_indexer_[idx] = map_idx;
  }

  void AddEdge(int from, int to, FlowType cap) {
    node p;
    p.v = to;
    p.cap = cap;
    p.next = head_[from];
    head_[from] = static_cast<int>(edges_.size());
    edges_.emplace_back(p);
  }

  std::vector<node> edges_;
  std::vector<int> head_;

  std::unordered_map<int, int> vertex_indexer_;
  int used_index_ = 0;
};

#include <string>

class FoxAndCity {
 public:
  int minimalCost(const std::vector<std::string> linked,
                  const std::vector<int> want) {
    constexpr int kMaxCapacity = 1000000;
    int n = static_cast<int>(linked.size());
    MaxFlowSolver<int> solver;
    auto Index = [&](int u, int k) { return u * n + k; };
    int source = -1;
    int sink = -2;
    for (int i = 0; i < n; ++i) {
      if (i == 0) {
        solver.InsertEdge(Index(i, 0), sink, kMaxCapacity);
        continue;
      }

      solver.InsertEdge(source, Index(i, 0), kMaxCapacity);
      solver.InsertEdge(Index(i, n - 1), sink, kMaxCapacity);
      for (int j = 1; j < n; ++j) {
        solver.InsertEdge(Index(i, j - 1), Index(i, j),
                          (want[i] - j) * (want[i] - j));
      }
    }
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < n; ++j) {
        if (linked[i][j] == 'Y') {
          for (int k = 1; k < n; ++k) {
            solver.InsertEdge(Index(i, k), Index(j, k - 1), kMaxCapacity);
          }
        }
      }
    }
    return solver.MaxFlow(source, sink);
  }
};
posted @ 2018-07-29 12:27  朝拜明天19891101  阅读(399)  评论(0编辑  收藏  举报