結果
| 問題 |
No.5005 3-SAT
|
| ユーザー |
tomerun
|
| 提出日時 | 2022-04-29 16:20:49 |
| 言語 | Crystal (1.14.0) |
| 結果 |
AC
|
| 実行時間 | 1,557 ms / 2,000 ms |
| コード長 | 7,613 bytes |
| コンパイル時間 | 19,462 ms |
| 実行使用メモリ | 6,136 KB |
| スコア | 75,503 |
| 最終ジャッジ日時 | 2022-04-29 16:23:51 |
| 合計ジャッジ時間 | 176,807 ms |
|
ジャッジサーバーID (参考情報) |
judge14 / judge13 |
| 純コード判定しない問題か言語 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 100 |
ソースコード
START_TIME = Time.utc.to_unix_ms
TL = 1580
N = 2048
M = 256
INF = 1 << 29
RND = Random.new(2)
macro debug(msg)
{% if flag?(:trace) %}
STDERR.puts({{msg}})
{% end %}
end
macro debugf(format_string, *args)
{% if flag?(:trace) %}
STDERR.printf({{format_string}}, {{*args}})
{% end %}
end
class IndexSet
getter :upper
def initialize(@upper : Int32)
@que = [] of Int32
@pos = Array(Int32).new(@upper, -1)
end
def add(v)
if @pos[v] == -1
@pos[v] = @que.size
@que << v
end
end
def remove(v)
p = @pos[v]
b = @que[-1]
@que[p] = b
@que.pop
@pos[b] = p
@pos[v] = -1
end
def get_random
@que[RND.rand(@que.size)]
end
def size
@que.size
end
def to_s(io)
@que.to_s(io)
end
end
class Result
property :bits, :score
def initialize(@bits : Array(Int32), @score : Int32)
end
def to_s(io)
io << @bits.map { |v| v == -1 ? 0 : v }.reverse.join
end
end
struct Cond
getter :var, :val
def initialize(@var : Int32, @val : Int32)
end
end
alias Term = Tuple(Cond, Cond, Cond)
class Solver
def initialize
@terms = Array(Term).new(N) do
a, b, c, p, q, r = read_line.split.map(&.to_i)
{Cond.new(a, p), Cond.new(b, q), Cond.new(c, r)}
end
@var_pos = Array(Array(Tuple(Int32, Int32))).new(M) { [] of Tuple(Int32, Int32) }
N.times do |i|
3.times do |j|
term = @terms[i][j]
@var_pos[term.var] << {i, term.val}
end
end
@best_result = Result.new(Array.new(M, -1), 0)
@ans = Array(Int32).new(M, -1)
@search_order = [0, 1, 2]
@dfs_count = 0
@eval = Array(Int32).new(3, 0)
@ok_count = Array(Int32).new(N, 0)
@ng_count = Array(Int32).new(N, 0)
@pass = Array(Bool).new(N) do |i|
ts = @terms[i]
[[0, 1], [1, 2], [2, 0]].any? { |ps| ts[ps[0]].var == ts[ps[1]].var && ts[ps[0]].var != ts[ps[1]].var }
end
end
def solve(timelimit)
start_time = Time.utc.to_unix_ms
before_time = start_time
solve_single()
after_time = Time.utc.to_unix_ms
worst_time = after_time - before_time
turn = 0
while true
before_time = after_time
if before_time + worst_time > timelimit
debug("turn:#{turn} worst_time:#{worst_time}")
break
end
solve_single()
after_time = Time.utc.to_unix_ms
worst_time = {worst_time, after_time - before_time}.max
turn += 1
end
STDERR.puts("validate_score:#{score(@best_result.bits)}")
return @best_result
end
def solve_single
@ans.fill(-1)
@dfs_count = 0
@ok_count.fill(0)
@ng_count.fill(0)
pos = 0
while pos < N
if try_next(pos)
while pos < N && @ok_count[pos] > 0
pos += 1
end
if pos > @best_result.score
@best_result.score = pos
@best_result.bits[0, M] = @ans
debug("best_score:#{pos}")
end
# if score(@ans) != pos
# debug("validate_score:#{score(@ans)} score:#{pos}")
# exit
# end
else
break
end
end
end
def try_next(pos)
shuffle(@search_order)
3.times do |i|
t = @terms[pos][@search_order[i]]
if @ans[t.var] == -1
@ans[t.var] = t.val
@var_pos[t.var].each do |ps|
p, v = ps
if v == t.val
@ok_count[p] += 1
else
@ng_count[p] += 1
end
end
return true
end
end
set = IndexSet.new(N)
set.add(pos)
used = Set(Int32).new
@dfs_count = 0
return try_dfs(pos, set, used)
end
def try_dfs(pos, set, used)
# debug("try_dfs:#{pos} #{set} #{used}")
if set.size == 0
return true
end
if @dfs_count > 10000
return false
end
cur = set.get_random
# set.remove(cur)
# if @ok_count[cur] > 0
# if try_dfs(pos, set, used)
# return true
# else
# set.add(cur)
# return false
# end
# end
shuffle(@search_order)
@dfs_count += 1
3.times do |i|
t = @terms[cur][@search_order[i]]
next if used.includes?(t.var)
used << t.var
old = @ans[t.var]
@ans[t.var] = t.val
@var_pos[t.var].each do |ps|
p, v = ps
if v == t.val
@ok_count[p] += 1
@ng_count[p] -= 1
if p <= pos && @ok_count[p] == 1
set.remove(p)
end
elsif old != -1
@ok_count[p] -= 1
@ng_count[p] += 1
if p <= pos && @ok_count[p] == 0
set.add(p)
end
end
# debug("@ok_count[#{p}]=#{@ok_count[p]}")
# debug("@ng_count[#{p}]=#{@ng_count[p]}")
end
if try_dfs(pos, set, used)
return true
end
used.delete(t.var)
@ans[t.var] = old
@var_pos[t.var].each do |ps|
p, v = ps
if v == t.val
@ok_count[p] -= 1
@ng_count[p] += 1
if p <= pos && @ok_count[p] == 0
set.add(p)
end
elsif old != -1
@ok_count[p] += 1
@ng_count[p] -= 1
if p <= pos && @ok_count[p] == 1
set.remove(p)
end
end
end
end
# set.add(cur)
return false
end
def solve_single2
@ans.fill(-1)
@dfs_count = 0
@ok_count.fill(0)
@ng_count.fill(0)
dfs(0)
end
def dfs(pos)
if @pass[pos]
dfs(pos + 1)
end
if pos > @best_result.score
@best_result.score = pos
@best_result.bits[0, M] = @ans
debug("best_score:#{pos}")
end
if @dfs_count > 1000
return
end
if @terms[pos].any? { |t| @ans[t.var] == t.val }
dfs(pos + 1)
else
3.times do |i|
t = @terms[pos][i]
if @ans[t.var] != -1
@eval[i] = -INF
next
end
@eval[i] = RND.rand(5000000)
@var_pos[t.var].each do |ps|
p, v = ps
next if p <= pos
if v == t.val
if @ok_count[p] == 0
# @eval[i] += N - p
end
else
if @ok_count[p] != 0
# @eval[i] -= (N - p) * ((@ng_count[p] + 1) ** 2)
if p <= @best_result.score && @ng_count[p] == 2
@eval[i] -= INF * 2
end
end
end
end
end
# debug(@eval)
cands = 3.times.select { |i| @eval[i] > -INF }.to_a
return if cands.empty?
@dfs_count += 1 if cands.size > 1
cands.sort_by { |i| -@eval[i] }.each do |ti|
t = @terms[pos][ti]
@ans[t.var] = t.val
@var_pos[t.var].each do |ps|
p, v = ps
if p > pos
if v == t.val
@ok_count[p] += 1
else
@ng_count[p] += 1
end
end
end
dfs(pos + 1)
@var_pos[t.var].each do |ps|
p, v = ps
if p > pos
if v == t.val
@ok_count[p] -= 1
else
@ng_count[p] -= 1
end
end
end
@ans[t.var] = -1
end
end
end
def shuffle(a)
(a.size - 1).times do |i|
pos = RND.rand(a.size - i) + i
a[i], a[pos] = a[pos], a[i]
end
end
def score(ans)
N.times do |i|
if @terms[i].all? { |t| ans[t.var] != t.val }
return i
end
end
return N
end
end
def main
solver = Solver.new
res = solver.solve(START_TIME + TL)
puts res
{% if flag?(:local) %}
STDERR.puts("score:#{res.score}")
{% end %}
end
main
tomerun