blog.bouzuya.net

2023-05-23 フルリモートではペアプロのほうが無難な選択肢である可能性

オフライン前提では極端な選択肢に見えたペアプロが、オンライン(フルリモート)前提ではコミュニケーションの面でオフラインの頃に近づけた中間的な選択肢になっているように見える、という話を今日のブログに書きたい。

https://iris.to/note1t00necqy7yjjvszj8lg0mdx5a6p6uutmcurvvntkqs73hf85azfs55djru

ペアプロについてぼくの中で新しい見方がある。それがフルリモート前提だとソロよりもペアのほうが無難な選択肢なのではという見方だ。

オフライン前提だったころはソロが基本だった。ペアプロのことを知ったときに単純計算で工数が倍になるけど大丈夫なのかと思った。オフラインにおけるペアは極端な選択肢に見えた。

ただ状況が変わっていまはオンライン。フルリモートが前提になってきた。

フルリモート前提でも以前と同様にソロを基本するケースも多いと思うけど、現職ではペア・モブが基本になっている (実際にはペア・モブのような形で集まりつつも、ソロで動くこともあり、ペアプロとはやや違う「日替わりバディ制度」的なものなのだけど) 。そういう環境で働いてみて気づいたことがある。

それが「フルリモート前提の環境において、コミュニケーションの観点だと、ソロのほうが極端な選択肢である」ということ。

オフライン前提だとすぐ近くに人が居るのは当然で、そこでのコミュニケーションコストは低いのだけど、フルリモート前提だと非同期でのテキストコミュニケーションだったり居るのかを確認するところからだったりとコミュニケーションコストが高くなる。

フルリモート前提の環境ではペアプロの形を取ることでコミュニケーションの観点でオフラインの環境に近づけることができる。

あるいはフルリモート前提だとソロのほうがむしろコミュニケーションの観点ではオフラインから最も離れた極端な形態と言ってもいいかもしれない。

ぼくの中では面白い発見だった。

逆に言うと、フルリモートという形態はオフラインとは異質のコミュニケーションが要求されるし、オフラインと似たコミュニケーションを取るためには極端に思えたペアプロ並のコストが要求されるのだと思った。


use std::collections::VecDeque;

use proconio::{input, marker::Usize1};

macro_rules! chmin {
    ($min_v: expr, $v: expr) => {
        if $v < $min_v {
            $min_v = $v;
            true
        } else {
            false
        }
    };
}

fn adjacency_list(n: usize, uv: &[(usize, usize)]) -> Vec<Vec<usize>> {
    let mut e = vec![vec![]; n];
    for (u, v) in uv.iter().copied() {
        e[u].push(v);
        e[v].push(u);
    }
    e
}

fn dijkstra(n: usize, inf: usize, e: &[Vec<usize>], s: usize) -> Vec<usize> {
    use std::{cmp::Reverse, collections::BinaryHeap};
    let mut d = vec![inf; n];
    let mut pq = BinaryHeap::new();
    d[s] = 0;
    pq.push(Reverse((0, s)));
    while let Some(Reverse((w_u, u))) = pq.pop() {
        if w_u > d[u] {
            continue;
        }
        for v in e[u].iter().copied() {
            let w = w_u + 1;
            if w < d[v] {
                d[v] = w;
                pq.push(Reverse((w, v)));
            }
        }
    }
    d
}

fn main() {
    input! {
        n: usize,
        m: usize,
        uv: [(Usize1, Usize1); m],
        s: Usize1,
        k: usize,
        t: [Usize1; k],
    }

    let edges = adjacency_list(n, &uv);

    let t = std::iter::once(s)
        .chain(t.into_iter())
        .collect::<Vec<usize>>();

    let inf = 1 << 60;
    let mut dist_t = vec![];
    for t_i in t.iter().copied() {
        let dist_t_i = dijkstra(n, inf, &edges, t_i);
        let dist_t_i = t
            .iter()
            .copied()
            .map(|t_j| dist_t_i[t_j])
            .collect::<Vec<_>>();
        dist_t.push(dist_t_i);
    }

    let k = k + 1;
    let mut dp = vec![vec![inf; k]; 1 << k];
    dp[1][0] = 0_usize;
    let mut deque = VecDeque::new();
    deque.push_back((1, 0));
    while let Some((set, u)) = deque.pop_front() {
        for v in 0..k {
            if (set & (1 << v)) != 0 {
                continue;
            }
            if chmin!(dp[set | (1 << v)][v], dp[set][u] + dist_t[u][v]) {
                deque.push_back((set | (1 << v), v));
            }
        }
    }
    let ans = dp[(1 << k) - 1].iter().min().unwrap();
    println!("{}", ans);
}

今日のコミット。