拼多多笔试真题 9.6 - 看旗派舟(C++/Py/Java /Js/Go)

看旗派舟

拼多多 9月6号 笔试真题 第四题

拼多多真题目录点击查看: 拼多多 春招&秋招 笔试真题题库目录|笔试题库 + 算法考点详解

题目内容

江上两座水寨要按旧例比旗。我方与对方各备 m m m 艘快艇。寨中留下一张对阵册:我方第 i i i 艘对上对方第 j j j 艘时,若册上为 1 则我方得 1 分,若为 -1 则我方得 -1 分。比旗共 m m m 轮,每轮对方先从自己尚未出列的艇里派出一艘;我方看清来艇后,再从自己尚未出列的艇里派一艘应战。两艘艇对阵一次后都不再上场。

对方希望我方总分尽量低,我方希望总分尽量高,双方都按最优策略行动。胜负可以互相克制、甚至成环,并不存在绝对最强的一艘艇。请对每一场比旗,求出我方最终能拿到的总分。

约束:

  • 1 ≤ \le ≤ q q q ≤ \le ≤ 10 10 10
  • 1 ≤ \le ≤ m m m ≤ \le ≤ 10 2 10^2 102
  • 对阵册每个数只可能是 1-1

输入描述

第一行一个整数 q q q(1 ≤ \le ≤ q q q ≤ \le ≤ 10 10 10),表示比旗场数。

随后是 q q q 场,每场格式如下:

  • 第一行一个整数 m m m(1 ≤ \le ≤ m m m ≤ \le ≤ 10 2 10^2 102),表示每方快艇数量
  • 接下来 m m m 行,每行 m m m 个整数 g i , 0 , g i , 1 , ... , g i , m − 1 g_{i,0},g_{i,1},\ldots,g_{i,m-1} gi,0,gi,1,...,gi,m−1(每个为 1-1),表示我方第 i i i 艘对对方各艘的结果

输出描述

输出 q q q 行,每行一个整数,表示该场在双方最优策略下我方的总分。

样例1

输入

复制代码
2
1
-1
2
1 -1
1 1

输出

复制代码
-1
2

说明

  • 第一场只有一艘艇,册上是 -1,我方只能得 -1 分。
  • 第二场我方两艘都能在合适搭配下取胜,最大匹配为 2,总分 $2\times 2 - 2 = 2

样例2

输入

复制代码
1
3
1 1 -1
1 -1 -1
-1 -1 1

输出

复制代码
3

说明

三对都能配成我方获胜:例如 ( 0 , 1 ) (0,1) (0,1)、 ( 1 , 0 ) (1,0) (1,0)、 ( 2 , 2 ) (2,2) (2,2)。场数等于艇数,总分 $2\times 3 - 3 = 3

样例3

输入

复制代码
1
3
1 1 -1
-1 -1 -1
1 -1 -1

输出

复制代码
1

说明

我方最多赢 2 场(第二艘对谁都输),总分 $2\times 2 - 3 = 1

题解

思路

解题思路: 匈牙利算法

  1. 把"我方艇"和"对方艇"看成二分图,只有对阵结果为 1 时连边,求这个二分图的最大匹配。答案为2 × 最大匹配数 - m
  2. 把我方艇作为左边节点,对方艇作为右边节点。寻找最大g[i][j] == 1的最大匹配数量k。寻找最大匹配数量采用匈牙利算法
  3. 维护match[j]表示当前对方第 j 艘艇匹配到了我方哪艘艇。对于每一艘我方艇 i
    • 尝试寻找一个结果为 1 的对方艇 j
    • 如果 j 没有匹配,直接匹配.
    • 如果 j 已经匹配给其他我方艇,则尝试让原来的我方艇换一个位置.
    • 如果能成功找到增广路,匹配数 +1
  4. 算法总体时间复杂度为O(m^3)

C++

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int m;
vector<vector<int>> g;
vector<int> match;
vector<bool> vis;

// 寻找增广路
bool dfs(int u) {
    for (int v = 0; v < m; v++) {
        if (g[u][v] != 1 || vis[v]) {
            continue;
        }

        vis[v] = true;

        if (match[v] == -1 || dfs(match[v])) {
            match[v] = u;
            return true;
        }
    }

    return false;
}

int solve() {
    match.assign(m, -1);
    int maxMatch = 0;
    for (int i = 0; i < m; i++) {
        vis.assign(m, false);
        if (dfs(i)) {
            maxMatch++;
        }
    }
    // 得分 maxMatch - (m - maxMatch)
    return 2 * maxMatch - m;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int q;
    cin >> q;
    while(q --) {
        cin >> m;
        g.assign(m, vector<int>(m));
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < m; j++) {
                cin >> g[i][j];
            }
        }
        cout << solve() << endl;
    }
    return 0;
}

java

java 复制代码
import java.io.*;
import java.util.*;

public class Main {
    static int m;
    static int[][] g;
    static int[] match;
    static boolean[] vis;

    // 寻找增广路
    static boolean dfs(int u) {
        for (int v = 0; v < m; v++) {
            if (g[u][v] != 1 || vis[v]) {
                continue;
            }

            vis[v] = true;

            if (match[v] == -1 || dfs(match[v])) {
                match[v] = u;
                return true;
            }
        }

        return false;
    }

    static int solve() {
        match = new int[m];
        Arrays.fill(match, -1);

        int maxMatch = 0;

        for (int i = 0; i < m; i++) {
            vis = new boolean[m];

            if (dfs(i)) {
                maxMatch++;
            }
        }

        // 得分 maxMatch - (m - maxMatch)
        return 2 * maxMatch - m;
    }

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int q = Integer.parseInt(br.readLine().trim());

        while (q-- > 0) {
            m = Integer.parseInt(br.readLine().trim());

            g = new int[m][m];

            for (int i = 0; i < m; i++) {
                StringTokenizer st = new StringTokenizer(br.readLine());

                for (int j = 0; j < m; j++) {
                    g[i][j] = Integer.parseInt(st.nextToken());
                }
            }

            System.out.println(solve());
        }
    }
}

python

python 复制代码
import sys

m = 0
g = []
match = []
vis = []


# 寻找增广路
def dfs(u):
    for v in range(m):
        if g[u][v] != 1 or vis[v]:
            continue

        vis[v] = True

        if match[v] == -1 or dfs(match[v]):
            match[v] = u
            return True

    return False


def solve():
    global match, vis

    match = [-1] * m
    max_match = 0

    for i in range(m):
        vis = [False] * m

        if dfs(i):
            max_match += 1

    # 得分 maxMatch - (m - maxMatch)
    return 2 * max_match - m


def main():
    global m, g

    input = sys.stdin.readline

    q = int(input())

    while q > 0:
        q -= 1

        m = int(input())
        g = []

        for _ in range(m):
            g.append(list(map(int, input().split())))

        print(solve())


if __name__ == "__main__":
    main()

javascript

js 复制代码
const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

const input = [];

rl.on('line', line => {
    input.push(line.trim());
});

rl.on('close', () => {
    let index = 0;

    let m = 0;
    let g = [];
    let match = [];
    let vis = [];

    // 寻找增广路
    function dfs(u) {
        for (let v = 0; v < m; v++) {
            if (g[u][v] !== 1 || vis[v]) {
                continue;
            }

            vis[v] = true;

            if (match[v] === -1 || dfs(match[v])) {
                match[v] = u;
                return true;
            }
        }

        return false;
    }

    function solve() {
        match = new Array(m).fill(-1);

        let maxMatch = 0;

        for (let i = 0; i < m; i++) {
            vis = new Array(m).fill(false);

            if (dfs(i)) {
                maxMatch++;
            }
        }

        // 得分 maxMatch - (m - maxMatch)
        return 2 * maxMatch - m;
    }

    const q = Number(input[index++]);

    for (let caseNum = 0; caseNum < q; caseNum++) {
        m = Number(input[index++]);

        g = new Array(m);

        for (let i = 0; i < m; i++) {
            g[i] = input[index++].split(/\s+/).map(Number);
        }

        console.log(solve());
    }
});

Go

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
)

var m int
var g [][]int
var match []int
var vis []bool

// 寻找增广路
func dfs(u int) bool {
	for v := 0; v < m; v++ {
		if g[u][v] != 1 || vis[v] {
			continue
		}

		vis[v] = true

		if match[v] == -1 || dfs(match[v]) {
			match[v] = u
			return true
		}
	}

	return false
}

func solve() int {
	match = make([]int, m)

	for i := 0; i < m; i++ {
		match[i] = -1
	}

	maxMatch := 0

	for i := 0; i < m; i++ {
		vis = make([]bool, m)

		if dfs(i) {
			maxMatch++
		}
	}

	// 得分 maxMatch - (m - maxMatch)
	return 2*maxMatch - m
}

func main() {
	in := bufio.NewReader(os.Stdin)
	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()

	var q int
	fmt.Fscan(in, &q)

	for ; q > 0; q-- {
		fmt.Fscan(in, &m)

		g = make([][]int, m)

		for i := 0; i < m; i++ {
			g[i] = make([]int, m)

			for j := 0; j < m; j++ {
				fmt.Fscan(in, &g[i][j])
			}
		}

		fmt.Fprintln(out, solve())
	}
}
相关推荐
无限码力3 小时前
拼多多笔试真题 - 班次连窗日均(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·拼多多笔试题目题解·拼多多题库·拼多多机试真题
无限码力16 小时前
拼多多笔试真题题解 - 并箱放行(C++/Py/Java /Js/Go)
拼多多·拼多多笔试真题·拼多多笔试题解·拼多多9月6号笔试真题
无限码力1 天前
拼多多笔试真题 9.6 - 限次罐笼(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·拼多多笔试真题题解·拼多多笔试题解·拼多多9月6号笔试真题
无限码力13 天前
拼多多笔试真题 2026-8-30【唯一入栈出库序列】
算法·pdd笔试真题·拼多多春招笔试真题·拼多多秋招笔试真题·拼多多笔试真题题解·拼多多最新笔试题库
无限码力13 天前
2026-8-30拼多多笔试真题-哪个查阅窗能留空(C++/Py/Java /Js/Go)
算法·pdd·pdd笔试真题·拼多多春招笔试真题·拼多多秋招笔试真题·拼多多笔试真题题解·拼多多笔试题解
无限码力16 天前
pdd笔试真题-和差方程最少标定(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·pdd笔试真题·拼多多技术岗笔试真题·拼多多秋招笔试·拼多多笔试题解
无限码力16 天前
拼多多 春招&秋招 笔试真题题库目录|笔试题库 + 算法考点详解
算法·pdd笔试真题·pdd笔试真题题解·拼多多春招笔试真题·拼多多秋招笔试真题·拼多多笔试真题题解
无限码力17 天前
pdd笔试真题-驿站补给最短耗时(C++/Py/Java /Js/Go)
pdd·拼多多笔试真题·拼多多机试·拼多多技术岗笔试·pdd笔试真题·拼多多技术岗笔试真题·pdd笔试真题题解
无限码力1 个月前
拼多多笔试真题-评价展示序列(C++/Py/Java /Js/Go)
拼多多·pdd·拼多多机试·拼多多技术岗笔试·拼多多笔试·拼多多技术岗笔试真题