結果

問題 No.5007 Steiner Space Travel
ユーザー matsu7874matsu7874
提出日時 2022-07-30 17:45:15
言語 Rust
(1.77.0 + proconio)
結果
AC  
実行時間 9 ms / 1,000 ms
コード長 7,476 bytes
コンパイル時間 1,251 ms
実行使用メモリ 5,160 KB
スコア 7,232,007
最終ジャッジ日時 2022-07-30 17:45:28
合計ジャッジ時間 3,349 ms
ジャッジサーバーID
(参考情報)
judge10 / judge11
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 6 ms
5,160 KB
testcase_01 AC 7 ms
4,908 KB
testcase_02 AC 6 ms
4,904 KB
testcase_03 AC 6 ms
4,900 KB
testcase_04 AC 7 ms
4,900 KB
testcase_05 AC 6 ms
4,900 KB
testcase_06 AC 6 ms
4,904 KB
testcase_07 AC 6 ms
4,904 KB
testcase_08 AC 6 ms
4,900 KB
testcase_09 AC 6 ms
4,900 KB
testcase_10 AC 6 ms
4,904 KB
testcase_11 AC 9 ms
4,904 KB
testcase_12 AC 7 ms
4,904 KB
testcase_13 AC 7 ms
4,900 KB
testcase_14 AC 6 ms
5,160 KB
testcase_15 AC 6 ms
4,900 KB
testcase_16 AC 6 ms
4,900 KB
testcase_17 AC 6 ms
4,900 KB
testcase_18 AC 6 ms
4,900 KB
testcase_19 AC 7 ms
4,900 KB
testcase_20 AC 6 ms
4,900 KB
testcase_21 AC 6 ms
4,900 KB
testcase_22 AC 6 ms
4,904 KB
testcase_23 AC 6 ms
4,904 KB
testcase_24 AC 6 ms
4,904 KB
testcase_25 AC 6 ms
5,160 KB
testcase_26 AC 7 ms
4,904 KB
testcase_27 AC 6 ms
4,900 KB
testcase_28 AC 7 ms
4,908 KB
testcase_29 AC 6 ms
4,900 KB
権限があれば一括ダウンロードができます
コンパイルメッセージ
warning: value assigned to `t` is never read
 --> Main.rs:7:17
  |
7 |         let mut t = 0;
  |                 ^
  |
  = note: `#[warn(unused_assignments)]` on by default
  = help: maybe it is overwritten before being read?

warning: unused variable: `cluster_ids`
   --> Main.rs:131:5
    |
131 |     cluster_ids: &[usize],
    |     ^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_cluster_ids`
    |
    = note: `#[warn(unused_variables)]` on by default

warning: unused variable: `n`
   --> Main.rs:214:10
    |
214 |     let (n, m, planets) = read_input();
    |          ^ help: if this is intentional, prefix it with an underscore: `_n`

warning: 3 warnings emitted

ソースコード

diff #

static mut XORSHIFT1: u128 = 123456789;
static mut XORSHIFT2: u128 = 362436069;
static mut XORSHIFT3: u128 = 521288629;
static mut XORSHIFT4: u128 = 88675123;
fn xorshift() -> u128 {
    unsafe {
        let mut t = 0;
        t = XORSHIFT1 ^ (XORSHIFT1 << 11u128);
        XORSHIFT1 = XORSHIFT2;
        XORSHIFT2 = XORSHIFT3;
        XORSHIFT3 = XORSHIFT4;
        XORSHIFT4 = (XORSHIFT4 ^ (XORSHIFT4 >> 19u128)) ^ (t ^ (t >> 8u128));
        t
    }
}
fn read_input() -> (usize, usize, Vec<(i32, i32)>) {
    let (n, m) = {
        let mut s = String::new();
        std::io::stdin().read_line(&mut s).unwrap();
        let s = s.trim_end().to_owned();
        let mut ws = s.split_whitespace();
        let n: usize = ws.next().unwrap().parse().unwrap();
        let m: usize = ws.next().unwrap().parse().unwrap();
        (n, m)
    };
    let mut xy = vec![];
    for _ in 0..n {
        let mut s = String::new();
        std::io::stdin().read_line(&mut s).unwrap();
        let s = s.trim_end().to_owned();
        let mut ws = s.split_whitespace();
        let a: i32 = ws.next().unwrap().parse().unwrap();
        let b: i32 = ws.next().unwrap().parse().unwrap();
        xy.push((a, b));
    }
    (n, m, xy)
}
const MAX_X: i32 = 1000;
type Point = (i32, i32);

// fn dist(p: &Point, q: &Point) -> i32 {
//     (((p.0 - q.0) * (p.0 - q.0) + (p.1 - q.1) * (p.1 - q.1)) as f64).sqrt() as i32
// }
fn dist_powered(p: &Point, q: &Point) -> i32 {
    (p.0 - q.0) * (p.0 - q.0) + (p.1 - q.1) * (p.1 - q.1)
}
fn kmeans(points: &[Point], k: usize, max_iter: usize) -> (Vec<Point>, Vec<usize>) {
    let n = points.len();
    let mut centors = Vec::with_capacity(k);
    for _ in 0..k {
        centors.push((
            (xorshift() as i32).abs() % (MAX_X + 1),
            (xorshift() as i32).abs() % (MAX_X + 1),
        ));
    }
    let mut cluster_ids = vec![0; n];
    let mut cluster_sizes = vec![0; k];
    cluster_sizes[0] = n as i32;

    let mut updated = false;
    for loop_count in 0..max_iter {
        // 各点から最も近い代表点を探す
        for i in 0..n {
            let mut nearest_centor_id = 0;
            let mut nearest_centor_distance = dist_powered(&points[i], &centors[0]);
            for j in 1..k {
                let distance = dist_powered(&points[i], &centors[j]);
                if distance < nearest_centor_distance {
                    nearest_centor_distance = distance;
                    nearest_centor_id = j;
                }
            }
            if nearest_centor_id != cluster_ids[i] {
                cluster_sizes[cluster_ids[i]] -= 1;
                cluster_ids[i] = nearest_centor_id;
                cluster_sizes[nearest_centor_id] += 1;
                updated = true;
            }
        }
        // 代表点の座標をクラスタの中心に移動する
        let mut dxs = vec![0; k];
        let mut dys = vec![0; k];
        for i in 0..n {
            let cid = cluster_ids[i];
            dxs[cid] += points[i].0 - centors[cid].0;
            dys[cid] += points[i].1 - centors[cid].1;
        }
        for i in 0..k {
            if cluster_sizes[i] == 0 {
                continue;
            }
            centors[i].0 += dxs[i] / cluster_sizes[i];
            centors[i].1 += dys[i] / cluster_sizes[i];
        }
        if !updated {
            eprintln!("kmeans loop breaked at loop {}", loop_count);
            break;
        }
    }
    (centors, cluster_ids)
}

// fn tsp_dp(points:&[Point])->Vec<usize>{
//     let n = points.len();
//     let mut dp = vec![]

// }

const ALPHA: i32 = 5;
fn get_cost_coefficient(t1: usize, t2: usize) -> i32 {
    if t1 == PLANET {
        if t2 == PLANET {
            ALPHA * ALPHA
        } else {
            ALPHA
        }
    } else {
        if t2 == PLANET {
            ALPHA
        } else {
            1
        }
    }
}

const PLANET: usize = 1;
const STATION: usize = 2;
fn search_path(
    stations: &[Point],
    planets: &[Point],
    cluster_ids: &[usize],
) -> Vec<(usize, usize)> {
    let n = planets.len();
    let m = stations.len();

    // 全点対の最短経路を求める
    let mut next = vec![vec![0; n + m]; n + m];
    for i in 0..n + m {
        for j in 0..n + m {
            next[i][j] = j;
        }
    }
    let mut dist = vec![vec![i32::MAX / 4; n + m]; n + m];
    for i in 0..n + m {
        let p = if i < n { planets[i] } else { stations[i - n] };
        let tp = if i < n { PLANET } else { STATION };
        for j in 0..n + m {
            let q = if j < n { planets[j] } else { stations[j - n] };
            let tq = if i < n { PLANET } else { STATION };
            dist[i][j] = get_cost_coefficient(tp, tq) * dist_powered(&p, &q);
        }
    }
    for k in 0..n + m {
        for i in 0..n + m {
            for j in 0..n + m {
                if dist[i][k] + dist[k][j] < dist[i][j] {
                    dist[i][j] = dist[i][k] + dist[k][j];
                    next[i][j] = next[i][k];
                }
            }
        }
    }

    // 経路を作成する
    let mut path = vec![(PLANET, 0)];
    let mut visited = vec![false; planets.len()];
    visited[0] = true;
    let mut count_visited_planets = 1;

    let mut cur_id = 0;

    while count_visited_planets < planets.len() {
        // まだ到達していない惑星のなかで距離が最小のものに移動する
        let mut nearest_distance = i32::MAX;
        let mut nearest = (PLANET, 0);
        for i in 0..planets.len() {
            if visited[i] {
                continue;
            }
            // let distance =
            //     get_cost_coefficient(cur_type, PLANET) * dist_powered(&cur_point, &planets[i]);
            if dist[cur_id][i] < nearest_distance {
                nearest_distance = dist[cur_id][i];
                nearest = (PLANET, i);
            }
        }

        // 経路に追加する
        if nearest.0 == PLANET {
            count_visited_planets += 1;
            visited[nearest.1] = true;

            // 経路復元
            let mut cur = cur_id;
            while cur != nearest.1 {
                cur = next[cur][nearest.1];
                path.push((if cur < n { PLANET } else { STATION }, cur % n));
            }
        }
        path.push(nearest);
        cur_id = nearest.1;
    }

    // planet0に帰る
    let mut cur = cur_id;
    while cur != 0 {
        cur = next[cur][0];
        path.push((if cur < n { PLANET } else { STATION }, cur % n));
    }

    path
}
fn main() {
    let (n, m, planets) = read_input();
    let (stations, cluster_ids) = kmeans(&planets, m, 1000);
    eprintln!("stations: {:?}", stations);
    let path = search_path(&stations, &planets, &cluster_ids);
    assert!(path.len() <= 100000);

    for (x, y) in stations.iter() {
        println!("{} {}", x, y);
    }
    println!("{}", path.len());
    for (t, i) in path.iter() {
        println!("{} {}", t, i + 1);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_kmeans() {
        let points = vec![(10, 10), (1000, 1000), (10, 5), (10, 6)];
        let (centors, cluster_id) = kmeans(&points, 2, 100);
        eprintln!("centors:{:?}", centors);
        eprintln!("cluster_id:{:?}", cluster_id);
        assert_eq!(cluster_id[0], cluster_id[2]);
        assert_eq!(cluster_id[0], cluster_id[3]);
        assert_eq!(centors[cluster_id[0]], (10, 7));
        assert_eq!(centors[cluster_id[1]], (1000, 1000));
    }
}
0