const MaxT: number = 10000; const MaxN: number = 27; const MaxCost: number = 1e8; type Result = Ok | Err; type Ok = { tag: "Yes"; data: Success }; type Err = { tag: "No"; data: Error }; const Ok = (data: Success): Ok => ({ tag: "Yes", data }); const Err = (data: Error): Err => ({ tag: "No", data }); function isSortingNetwork( n: number, cmps: [number, number][] ): Result { const state_zero: number = 0; const state_one: number = 1; const state_unknown: number = 2; // initial state: all elements are unknown const stack: [number, number[], number, number][] = [ [0, Array(n).fill(state_unknown), 0, n - 1], ]; const unused: boolean[] = Array(cmps.length).fill(true); const unsorted: boolean[] = Array(n - 1).fill(false); const m = cmps.length; // branch loop a: while (stack.length > 0) { // get branch state // i: index of cmps // p: state of each element // z: leading index of non-zero elements // o: trailing index of non-one elements let [i, p, z, o] = stack.pop()!; // CEs (compare/exchange elements) loop while (i < m) { // get next comparison let [a, b] = cmps[i++]; if (p[a] === state_zero || p[b] === state_one) { // (0, 0) or (1, 1) or (0, 1) or (0, ?) or (?, 1), no operation, continue to next CE } else if (p[a] === state_unknown && p[b] === state_unknown) { unused[i - 1] = false; // both elements are unknown // branch into (0, 0) and (?, 1) // copy state for (0, 0) new branch // set state for (?, 1) current branch let q = p.slice(); q[a] = state_zero; q[b] = state_zero; p[b] = state_one; // find 'q' leading non-zero element for (let j = z; j < o; ++j) { if (q[j] !== state_zero) { // if not sorted, push branch into stack stack.push([i, q, j, o]); break; } } // find p trailing non-one element if p is not sorted while (p[o] === state_one) { // if p is '0...01...1' or '0...0?1...1', if (z === --o) { // p is sorted, continue to next branch continue a; } } } else { unused[i - 1] = false; // if (1, 0) or (?, 0) or (1, ?), swap elements [p[a], p[b]] = [p[b], p[a]]; // find p leading non-zero element if p is not sorted while (p[z] === state_zero) { // if p is '0...01...1' or '0...0?1...1', if (++z === o) { // p is sorted, continue to next branch continue a; } } // find p trailing non-one element if p is not sorted while (p[o] === state_one) { // if p is '0...01...1' or '0...0?1...1', if (z === --o) { // p is sorted, continue to next branch continue a; } } } } // if p is not sorted for (let j = 0; j < n - 1; ++j) { if (p[j] !== state_zero && p[j + 1] !== state_one) { unsorted[j] = true; } } } if (unsorted.some((x) => x)) { return Err(unsorted); } // if p is sorted for all branches return Ok(unused); } function main(): void { const input: string[] = require("fs") .readFileSync("/dev/stdin", "utf8") .split("\n"); let index = 0; const t = parseInt(input[index++], 10); if (t > MaxT) throw new Error(`t must be <= ${MaxT}`); // phi = (1 + sqrt(5)) / 2 : golden ratio const phi = Math.sqrt(1.25) + 0.5; // testcases cost <= 1e8 let cost = 0.0; for (let i = 0; i < t; ++i) { const [n, m] = input[index++].split(" ").map((str) => parseInt(str, 10)); if (!(2 <= n && n <= MaxN && 1 <= m && m <= (n * (n - 1)) / 2)) throw new Error("Invalid n or m"); cost += m * Math.pow(phi, n); if (cost > MaxCost) throw new Error(`Cost must be <= ${MaxCost}`); // 1-indexed to 0-indexed const va: number[] = input[index++].split(" ").map((str) => parseInt(str, 10) - 1); const vb: number[] = input[index++].split(" ").map((str) => parseInt(str, 10) - 1); const cmps: [number, number][] = va.map((a, i) => [a, vb[i]]); if (cmps.length !== m) throw new Error("Invalid cmps length"); if (cmps.some(([a, b]) => !(0 <= a && a < b && b < n))) throw new Error("Invalid a or b"); const { data, tag } = isSortingNetwork(n, cmps); console.log(tag); if (tag === "Yes") { if (data.length !== m) throw new Error("Invalid data length"); console.log(data.filter((x) => x).length); console.log( data .map((x, i) => (x ? i + 1 : 0)) .filter((x) => x) .join(" ") ); } else if (tag === "No") { if (data.length !== n - 1) throw new Error("Invalid data length"); console.log(data.filter((x) => x).length); console.log( data .map((x, i) => (x ? i + 1 : 0)) .filter((x) => x) .join(" ") ); } } } main();