具有轻微约束的数字对中的最大唯一性

时间:2014-12-04 11:21:51

标签: algorithm max unique max-flow

这是您的算法挑战,

我有[0..100]个数字对的列表,我需要找到最大唯一&#34; 左数< / EM>&#34;同时确保不超过3 的&#34; 正确的号码&#34;。

这是一个例子

  • (1, 1)
  • (2, 1)
  • (3, 1)
  • (4, 1)
  • (5, 1)
  • (6, 1)
  • (7, 1)
  • (1, 2)
  • (4, 2)
  • (1, 3)
  • (2, 3)
  • (5, 4)

结果将是: 7 。我们将采取:(3, 1)(6, 1)(7, 1)(1, 2)(4, 2)(2, 3)(5, 4)

无论出于何种原因,我似乎找不到任何其他方式而不是粗暴强迫它......

非常感谢任何帮助:)

2 个答案:

答案 0 :(得分:2)

您可以将此问题表达为最大流量问题:

使容量1的边缘从源节点到左侧的每个数字。

将容量3的边缘从每个正确的数字扩展到汇聚节点。

为每对形式(a,b)从左数字a到右数字b创建容量1的边缘。

计算此网络中从源到接收器的最大流量。

答案 1 :(得分:0)

如果有人对此实施感兴趣,请参阅push–relabel maximum flow algorithmrelabel-to-front选项规则的红宝石版本。

def relabel_to_front(capacities, source, sink)
  n      = capacities.length
  flow   = Array.new(n) { Array.new(n, 0) }
  height = Array.new(n, 0)
  excess = Array.new(n, 0)
  seen   = Array.new(n, 0)
  queue  = (0...n).select { |i| i != source && i != sink }.to_a

  height[source] = n - 1
  excess[source] = Float::INFINITY
  (0...n).each { |v| push(source, v, capacities, flow, excess) }

  p = 0
  while p < queue.length
    u = queue[p]
    h = height[u]
    discharge(u, capacities, flow, excess, seen, height, n)
    if height[u] > h
      queue.unshift(queue.delete_at(p))
      p = 0
    else
      p += 1
    end
  end

  flow[source].reduce(:+)
end

def push(u, v, capacities, flow, excess)
  residual_capacity = capacities[u][v] - flow[u][v]
  send = [excess[u], residual_capacity].min
  flow[u][v] += send
  flow[v][u] -= send
  excess[u] -= send
  excess[v] += send
end

def discharge(u, capacities, flow, excess, seen, height, n)
  while excess[u] > 0
    if seen[u] < n
      v = seen[u]
      if capacities[u][v] - flow[u][v] > 0 && height[u] > height[v]
        push(u, v, capacities, flow, excess)
      else
        seen[u] += 1
      end
    else
      relabel(u, capacities, flow, height, n)
      seen[u] = 0
    end
  end
end

def relabel(u, capacities, flow, height, n)
  min_height = Float::INFINITY
  (0...n).each do |v|
    if capacities[u][v] - flow[u][v] > 0
      min_height = [min_height, height[v]].min
      height[u] = min_height + 1
    end
  end
end

这是将数字对转换为数组

的容量数组的代码
user_ids = Set.new
post_ids = Set.new

pairs.each do |p|
  user_ids << p[:user_id]
  post_ids << p[:post_id]
end

index_of_user_id = {}
index_of_post_id = {}

user_ids.each_with_index { |user_id, index| index_of_user_id[user_id] = 1 + index }
post_ids.each_with_index { |post_id, index| index_of_post_id[post_id] = 1 + index + user_ids.count }

source = 0
sink = user_ids.count + post_ids.count + 1
n = sink + 1

capacities = Array.new(n) { Array.new(n, 0) }
# source -> user_ids = 1
index_of_user_id.values.each { |i| capacities[source][i] = 1 }
# user_ids -> post_ids = 1
pairs.each { |p| capacities[index_of_user_id[p[:user_id]]][index_of_post_id[p[:post_id]]] = 1 }
# post_ids -> sink = 3
index_of_post_id.values.each { |i| capacities[i][sink] = 3 }