結果
| 問題 |
No.5005 3-SAT
|
| ユーザー |
👑 terry_u16
|
| 提出日時 | 2022-04-29 17:32:58 |
| 言語 | Rust (1.83.0 + proconio) |
| 結果 |
AC
|
| 実行時間 | 1,982 ms / 2,000 ms |
| コード長 | 11,945 bytes |
| コンパイル時間 | 1,151 ms |
| 実行使用メモリ | 6,952 KB |
| スコア | 26,211 |
| 最終ジャッジ日時 | 2022-04-29 17:36:25 |
| 合計ジャッジ時間 | 205,642 ms |
|
ジャッジサーバーID (参考情報) |
judge13 / judge12 |
| 純コード判定しない問題か言語 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 100 |
ソースコード
use std::time::Instant;
macro_rules! get {
($t:ty) => {
{
let mut line: String = String::new();
std::io::stdin().read_line(&mut line).unwrap();
line.trim().parse::<$t>().unwrap()
}
};
($($t:ty),*) => {
{
let mut line: String = String::new();
std::io::stdin().read_line(&mut line).unwrap();
let mut iter = line.split_whitespace();
(
$(iter.next().unwrap().parse::<$t>().unwrap(),)*
)
}
};
($t:ty; $n:expr) => {
(0..$n).map(|_|
get!($t)
).collect::<Vec<_>>()
};
($($t:ty),*; $n:expr) => {
(0..$n).map(|_|
get!($($t),*)
).collect::<Vec<_>>()
};
($t:ty ;;) => {
{
let mut line: String = String::new();
std::io::stdin().read_line(&mut line).unwrap();
line.split_whitespace()
.map(|t| t.parse::<$t>().unwrap())
.collect::<Vec<_>>()
}
};
($t:ty ;; $n:expr) => {
(0..$n).map(|_| get!($t ;;)).collect::<Vec<_>>()
};
}
#[allow(unused_macros)]
macro_rules! chmin {
($base:expr, $($cmps:expr),+ $(,)*) => {{
let cmp_min = min!($($cmps),+);
if $base > cmp_min {
$base = cmp_min;
true
} else {
false
}
}};
}
#[allow(unused_macros)]
macro_rules! chmax {
($base:expr, $($cmps:expr),+ $(,)*) => {{
let cmp_max = max!($($cmps),+);
if $base < cmp_max {
$base = cmp_max;
true
} else {
false
}
}};
}
#[allow(unused_macros)]
macro_rules! min {
($a:expr $(,)*) => {{
$a
}};
($a:expr, $b:expr $(,)*) => {{
std::cmp::min($a, $b)
}};
($a:expr, $($rest:expr),+ $(,)*) => {{
std::cmp::min($a, min!($($rest),+))
}};
}
#[allow(unused_macros)]
macro_rules! max {
($a:expr $(,)*) => {{
$a
}};
($a:expr, $b:expr $(,)*) => {{
std::cmp::max($a, $b)
}};
($a:expr, $($rest:expr),+ $(,)*) => {{
std::cmp::max($a, max!($($rest),+))
}};
}
#[allow(unused_macros)]
macro_rules! mat {
($e:expr; $d:expr) => { vec![$e; $d] };
($e:expr; $d:expr $(; $ds:expr)+) => { vec![mat![$e $(; $ds)*]; $d] };
}
#[derive(Debug, Clone, Copy)]
struct Requirement {
digit: usize,
value: usize,
}
#[derive(Debug, Clone)]
struct Choice {
requirements: [Requirement; 3],
}
#[derive(Debug, Clone)]
struct Input {
since: Instant,
choices: Vec<Choice>,
}
const CHOICES_COUNT: usize = 2048;
const DIGIT_LEN: usize = 256;
const TIME_LIMIT: f64 = 1.98;
fn main() {
let input = read_input();
let solution = solve(&input);
write_output(&solution);
}
fn read_input() -> Input {
let mut choices = vec![];
let mut counts = vec![0; DIGIT_LEN];
for _ in 0..CHOICES_COUNT {
let (a, b, c, p, q, r) = get!(usize, usize, usize, usize, usize, usize);
counts[a] += 1;
counts[b] += 1;
counts[c] += 1;
let requirements = [
Requirement { digit: a, value: p },
Requirement { digit: b, value: q },
Requirement { digit: c, value: r },
];
let choice = Choice { requirements };
choices.push(choice);
}
// TODO: 重なるケースとか真面目に見た方がいいかも
for choice in choices.iter_mut() {
choice
.requirements
.sort_unstable_by(|r0, r1| counts[r0.digit].cmp(&counts[r1.digit]));
}
let since = Instant::now();
let input = Input { since, choices };
input
}
fn solve(input: &Input) -> Vec<usize> {
let init_solution = solve_rand(&input, 0.1);
let solution = annealing(input, init_solution, TIME_LIMIT - 0.1);
to_answer(input, &solution)
}
fn solve_rand(input: &Input, duration: f64) -> Vec<usize> {
let mut best_solution = vec![0; DIGIT_LEN];
let mut best_score = 0;
let mut solution = vec![0; DIGIT_LEN];
let mut counts = vec![0; DIGIT_LEN];
let mut rng = Xorshift::new();
let mut valid_choices = vec![];
'main: while (Instant::now() - input.since).as_secs_f64() < duration {
solution.fill(0);
counts.fill(0);
for (i, choice) in input.choices.iter().enumerate() {
valid_choices.clear();
for req in choice.requirements.iter() {
if counts[req.digit] == 0 || solution[req.digit] == req.value {
valid_choices.push(req);
}
}
if valid_choices.len() == 0 {
if chmax!(best_score, i) {
best_solution = solution.clone();
}
continue 'main;
}
let index = rng.rand(valid_choices.len());
let choice = valid_choices[index];
solution[choice.digit] = choice.value;
counts[choice.digit] += 1;
}
best_score = input.choices.len();
best_solution = solution.clone();
}
eprintln!("score: {}", best_score);
best_solution
}
fn annealing(input: &Input, initial_solution: Vec<usize>, duration: f64) -> Vec<usize> {
let mut solution = initial_solution;
let mut best_solution = solution.clone();
let mut current_score = calc_custom_score(input, &solution);
let mut best_score = calc_score(input, &solution);
let mut all_iter = 0;
let mut valid_iter = 0;
let mut accepted_count = 0;
let mut update_count = 0;
let mut rng = Xorshift::with_seed(42);
let duration_inv = 1.0 / duration;
let since = std::time::Instant::now();
let mut time = 0.0;
let temp0 = 1e1;
let temp1 = 1e-1;
let mut inv_temp = 1.0 / temp0;
while time < 1.0 {
all_iter += 1;
if (all_iter & ((1 << 4) - 1)) == 0 {
time = (std::time::Instant::now() - since).as_secs_f64() * duration_inv;
let temp = f64::powf(temp0, 1.0 - time) * f64::powf(temp1, time);
inv_temp = 1.0 / temp;
}
let mut stack = vec![];
let index = if (current_score as usize) < CHOICES_COUNT && rng.rand(5) == 0 {
current_score as usize
} else {
rng.rand(solution.len())
};
let add = rng.rand(2) + 1;
let new_choice = (solution[index] + add) % 3;
solution[index] = new_choice;
stack.push((index, add));
let base_req = &input.choices[index].requirements[new_choice];
let mut used = [false; DIGIT_LEN];
let mut values = [0; DIGIT_LEN];
for (sol, choice) in solution[..(index + 1)].iter().zip(input.choices.iter()) {
let req = &choice.requirements[*sol];
if !used[req.digit] {
used[req.digit] = true;
values[req.digit] = req.value;
}
}
let mut candidates = vec![];
for i in 0..solution.len() {
if i == index {
continue;
}
let reqs = &input.choices[i].requirements;
let req = &reqs[solution[i]];
if req.digit == base_req.digit && req.value != base_req.value {
candidates.clear();
for (i, req) in reqs.iter().enumerate() {
if req.digit == base_req.digit && req.value != base_req.value {
candidates.push(i);
} else {
candidates.push(i);
candidates.push(i);
}
}
let new_choice = candidates[rng.rand(candidates.len())];
let add = (new_choice + 3 - solution[i]) % 3;
solution[i] = new_choice;
stack.push((i, add));
}
}
// スコア計算
let new_score = calc_custom_score(input, &solution);
let score_diff = new_score - current_score;
if score_diff >= 0 || rng.randf() < f64::exp(score_diff as f64 * inv_temp) {
// 解の更新
current_score = new_score;
accepted_count += 1;
if chmax!(best_score, calc_score(input, &solution)) {
best_solution = solution.clone();
update_count += 1;
}
} else {
// ロールバック
while let Some((i, add)) = stack.pop() {
solution[i] = (solution[i] + 3 - add) % 3;
}
}
valid_iter += 1;
}
eprintln!("===== annealing =====");
eprintln!("score : {}", best_score);
eprintln!("all iter : {}", all_iter);
eprintln!("valid iter : {}", valid_iter);
eprintln!("accepted : {}", accepted_count);
eprintln!("updated : {}", update_count);
eprintln!("");
eprintln!("score: {}", best_score);
best_solution
}
fn calc_score(input: &Input, solution: &[usize]) -> i32 {
let mut used = [false; DIGIT_LEN];
let mut values = [0; DIGIT_LEN];
for (i, (solution, choice)) in solution.iter().zip(input.choices.iter()).enumerate() {
let req = choice.requirements[*solution];
if used[req.digit] && values[req.digit] != req.value {
return i as i32;
}
used[req.digit] = true;
values[req.digit] = req.value;
}
CHOICES_COUNT as i32
}
fn calc_custom_score(input: &Input, solution: &[usize]) -> i32 {
let mut used = [false; DIGIT_LEN];
let mut values = [0; DIGIT_LEN];
let mut streak = 100;
let mut score = calc_score(input, solution);
for (solution, choice) in solution.iter().zip(input.choices.iter()) {
let req = choice.requirements[*solution];
if used[req.digit] && values[req.digit] != req.value {
score += streak * streak;
streak = 0;
} else {
streak += 1;
}
used[req.digit] = true;
values[req.digit] = req.value;
}
score += streak * streak;
score
}
fn to_answer(input: &Input, solution: &[usize]) -> Vec<usize> {
let mut used = [false; DIGIT_LEN];
let mut values = vec![0; DIGIT_LEN];
for (solution, choice) in solution.iter().zip(input.choices.iter()) {
let req = choice.requirements[*solution];
if used[req.digit] && values[req.digit] != req.value {
return values;
}
used[req.digit] = true;
values[req.digit] = req.value;
}
values
}
fn write_output(solution: &[usize]) {
let mut result = String::new();
for v in solution.iter().rev() {
if *v == 0 {
result.push('0');
} else {
result.push('1');
}
}
println!("{}", result);
}
#[derive(Debug)]
#[allow(dead_code)]
pub struct Xorshift {
seed: usize,
}
impl Xorshift {
#[allow(dead_code)]
pub fn new() -> Xorshift {
Xorshift {
seed: 0xf0fb588ca2196dac,
}
}
#[allow(dead_code)]
pub fn with_seed(seed: usize) -> Xorshift {
Xorshift { seed: seed }
}
#[inline]
#[allow(dead_code)]
pub fn next(&mut self) -> usize {
self.seed = self.seed ^ (self.seed << 13);
self.seed = self.seed ^ (self.seed >> 7);
self.seed = self.seed ^ (self.seed << 17);
self.seed
}
#[inline]
#[allow(dead_code)]
pub fn rand(&mut self, m: usize) -> usize {
self.next() % m
}
#[inline]
#[allow(dead_code)]
// 0.0 ~ 1.0
pub fn randf(&mut self) -> f64 {
use std::mem;
const UPPER_MASK: usize = 0x3FF0000000000000;
const LOWER_MASK: usize = 0xFFFFFFFFFFFFF;
let tmp = UPPER_MASK | (self.next() & LOWER_MASK);
let result: f64 = unsafe { mem::transmute(tmp) };
result - 1.0
}
}
terry_u16