拼多多笔试真题-多多的营救行动(C++/Py/Java /Js/Go)

多多的营救行动

拼多多技术岗 7月3号笔试 第二题

题目内容

多多国的公主被邪恶势力抓走后关押在地牢中,地牢中有 nnn 片区域,分别驻守着 111 个守卫,每个守卫会监视若干个固定的区域。多多勇士要营救公主,必须打倒所有守卫,同时保证行动不被暴露。具体规则如下:

  1. 多多武艺高强,可以使用暗器同时打倒 111 或 222 个守卫。
  2. 若一个守卫所在的区域没有被其他守卫监视,打倒他不会暴露行动。
  3. 若两个守卫都只被彼此监视,同时打倒他们不会暴露行动。注:AAA 只被 BBB 监视,BBB 只被 AAA 监视,但 AAA 和 BBB 可同时监视其它区域。
  4. 被打倒的守卫不再具备监视能力。
  5. 两个守卫不会在同一个区域。

输入描述

第 111 行:一个整数 nnn,表示守卫数量。 接下来 nnn 行,每行描述一个守卫,格式:xxx mmm y1y1y1 y2y2y2 ... ymymym

  • xxx:该守卫位置编号,从 111 开始,依次递增
  • mmm:该守卫监视的区域数量
  • y1y1y1 y2y2y2 ... ymymym:该守卫监视的区域编号,不会出现重复编号

约束条件

  • 1≤n≤1001 \le n \le 1001≤n≤100
  • 0≤m≤1000 \le m \le 1000≤m≤100
  • 1≤x,y≤1001 \le x,y \le 1001≤x,y≤100

输出描述

  • 如果可以击倒所有守卫而不暴露行动,输出 SUCCESSSUCCESSSUCCESS。
  • 否则输出不暴露行动下最少剩余未被打倒的守卫数量。

样例1

输入

复制代码
2
1 1 2
2 0

输出

复制代码
SUCCESS

题解

思路

  1. 根据题目输入进行建图,建立守卫 -> 监视区域的映射。

  2. 循环执行删除存活守卫,具体逻辑为

    1. 根据第一图建图存活守卫反向统计区域 -> 当前被谁监视的映射
    2. 根据第一步映射选择删除存活守卫:
      1. 优先选择单点可删除,如果存活守卫区域未被任何其它守卫监视,可删。
      2. 其次选择双点可删,找到x 只被 y 监视, y 只被 x 监视这种组合,可同时删除x y
    3. 如果一轮没有可删守卫可直接结束循环
  3. 第二步执行完成之后,如果所有守卫都被删除,输出SUCCESS,否则输出对应存活守卫数量即可

C++

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



int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin >> n;
    // 每个守卫监控区域
    vector<set<int>> guard(n);
    for (int i = 0; i < n; i++) {
        int x, m;
        cin >> x >> m;
        for (int j = 0; j < m; j++) {
            int y;
            cin >> y;
            // 1-base 转换为0-base
            guard[x - 1].insert(y - 1);
        }
    }
    // 存活守卫
    set<int> alive;
    for (int i = 0; i < n; i++) {
        alive.insert(i);
    }
    
    while (true) {
        bool flag = false;
        vector<set<int>> monitored(n);
        // 统计当前区间被监控数量
        for (auto x : alive) {
            for (auto v : guard[x]) {
                monitored[v].insert(x);
            }
        }
        
        // 找到未被监控区域
        int target = -1;
        for (auto x : alive) {
            if (monitored[x].empty()) {
                target = x;
                break;
            }
        }
        
        if (target != -1) {
            alive.erase(target);
            flag = true;
            continue;
        }
        
        // 没有找到未监控区域,尝试寻找成对打倒情况
        int a, b;
        a = b =  -1;
        for (int x : alive) {
            if (monitored[x].size() != 1) {
                continue;
            }
            // 拿到唯一监控哪一个人
            int y = *monitored[x].begin();
            // 也在存活列表中,并且y也只被x唯一监控
            if (alive.count(y) && monitored[y].size() == 1 && *monitored[y].begin() == x) {
                a = x;
                b = y;
                break;
            }
        }
        
        if (a != -1 && b != -1) {
            alive.erase(a);
            alive.erase(b);
            flag = true;
        }
        
        // 无法进行消除,直接结束
        if (!flag) {
            break;    
        }
    }
    
    
    if (alive.empty()) {
        cout << "SUCCESS";
    } else {
        cout << alive.size();
    }
    return 0;
    
}

java

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

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

        int n = Integer.parseInt(br.readLine());

        // 每个守卫监控区域
        List<Set<Integer>> guard = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            guard.add(new HashSet<>());
        }

        for (int i = 0; i < n; i++) {
            String[] parts = br.readLine().split(" ");
            int x = Integer.parseInt(parts[0]) - 1;
            int m = Integer.parseInt(parts[1]);

            int idx = 2;
            for (int j = 0; j < m; j++) {
                int y = Integer.parseInt(parts[idx++]) - 1;
                guard.get(x).add(y);
            }
        }

        // 存活守卫
        Set<Integer> alive = new HashSet<>();
        for (int i = 0; i < n; i++) alive.add(i);

        while (true) {
            boolean flag = false;

            List<Set<Integer>> monitored = new ArrayList<>();
            for (int i = 0; i < n; i++) monitored.add(new HashSet<>());

            // 统计当前区间被监控数量
            for (int x : alive) {
                for (int v : guard.get(x)) {
                    monitored.get(v).add(x);
                }
            }

            // 找到未被监控区域
            int target = -1;
            for (int x : alive) {
                if (monitored.get(x).isEmpty()) {
                    target = x;
                    break;
                }
            }

            if (target != -1) {
                alive.remove(target);
                continue;
            }

            // 成对删除
            int a = -1, b = -1;

            for (int x : alive) {
                if (monitored.get(x).size() != 1) continue;

                int y = monitored.get(x).iterator().next();

                if (alive.contains(y)
                        && monitored.get(y).size() == 1
                        && monitored.get(y).contains(x)) {
                    a = x;
                    b = y;
                    break;
                }
            }

            if (a != -1) {
                alive.remove(a);
                alive.remove(b);
                flag = true;
            }

            if (!flag && target == -1) break;
        }

        if (alive.isEmpty()) {
            System.out.println("SUCCESS");
        } else {
            System.out.println(alive.size());
        }
    }
}

python

python 复制代码
import sys

def solve():
    data = sys.stdin.read().strip().split()
    n = int(data[0])
    idx = 1

    # 每个守卫监控区域
    guard = [set() for _ in range(n)]

    for _ in range(n):
        x = int(data[idx]) - 1
        m = int(data[idx + 1])
        idx += 2

        for _ in range(m):
            y = int(data[idx]) - 1
            idx += 1
            guard[x].add(y)

    # 存活守卫
    alive = set(range(n))

    while True:
        flag = False

        # 统计当前区间被监控数量
        monitored = [set() for _ in range(n)]
        for x in alive:
            for v in guard[x]:
                monitored[v].add(x)

        # 找未被监控的
        target = -1
        for x in alive:
            if len(monitored[x]) == 0:
                target = x
                break

        if target != -1:
            alive.remove(target)
            continue

        # 成对删除
        a = b = -1

        for x in alive:
            if len(monitored[x]) != 1:
                continue
            y = next(iter(monitored[x]))

            if (y in alive and
                len(monitored[y]) == 1 and
                x in monitored[y]):
                a, b = x, y
                break

        if a != -1:
            alive.remove(a)
            alive.remove(b)
            flag = True

        if not flag and target == -1:
            break

    print("SUCCESS" if len(alive) == 0 else len(alive))


if __name__ == "__main__":
    solve()

javascript

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

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

let input = [];

rl.on("line", line => {
    input.push(...line.trim().split(/\s+/));
});

rl.on("close", () => {
    let idx = 0;
    const n = Number(input[idx++]);

    // 每个守卫监控区域
    const guard = Array.from({ length: n }, () => new Set());

    for (let i = 0; i < n; i++) {
        const x = Number(input[idx++]) - 1;
        const m = Number(input[idx++]);

        for (let j = 0; j < m; j++) {
            const y = Number(input[idx++]) - 1;
            guard[x].add(y);
        }
    }

    // 存活守卫
    const alive = new Set();
    for (let i = 0; i < n; i++) alive.add(i);

    while (true) {
        let flag = false;

        const monitored = Array.from({ length: n }, () => new Set());

        // 统计当前区间被监控数量
        for (let x of alive) {
            for (let v of guard[x]) {
                monitored[v].add(x);
            }
        }

        // 找未被监控
        let target = -1;
        for (let x of alive) {
            if (monitored[x].size === 0) {
                target = x;
                break;
            }
        }

        if (target !== -1) {
            alive.delete(target);
            continue;
        }

        // 成对删除
        let a = -1, b = -1;

        for (let x of alive) {
            if (monitored[x].size !== 1) continue;

            const y = [...monitored[x]][0];

            if (
                alive.has(y) &&
                monitored[y].size === 1 &&
                monitored[y].has(x)
            ) {
                a = x;
                b = y;
                break;
            }
        }

        if (a !== -1) {
            alive.delete(a);
            alive.delete(b);
            flag = true;
        }

        if (!flag && target === -1) break;
    }

    console.log(alive.size === 0 ? "SUCCESS" : alive.size);
});

Go

go 复制代码
package main

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

func main() {
	in := bufio.NewReader(os.Stdin)

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

	// 每个守卫监控区域
	guard := make([]map[int]bool, n)
	for i := 0; i < n; i++ {
		guard[i] = make(map[int]bool)
	}

	for i := 0; i < n; i++ {
		var x, m int
		fmt.Fscan(in, &x, &m)
		x--

		for j := 0; j < m; j++ {
			var y int
			fmt.Fscan(in, &y)
			y--
			guard[x][y] = true
		}
	}

	// 存活守卫
	alive := make(map[int]bool)
	for i := 0; i < n; i++ {
		alive[i] = true
	}

	for {
		flag := false

		// 统计当前区间被监控数量
		monitored := make([]map[int]bool, n)
		for i := 0; i < n; i++ {
			monitored[i] = make(map[int]bool)
		}

		for x := range alive {
			for v := range guard[x] {
				if alive[v] {
					monitored[v][x] = true
				}
			}
		}

		// 找未被监控
		target := -1
		for x := range alive {
			if len(monitored[x]) == 0 {
				target = x
				break
			}
		}

		if target != -1 {
			delete(alive, target)
			continue
		}

		// 成对删除
		a, b := -1, -1

		for x := range alive {
			if len(monitored[x]) != 1 {
				continue
			}

			var y int
			for k := range monitored[x] {
				y = k
			}

			if alive[y] && len(monitored[y]) == 1 {
				for k := range monitored[y] {
					if k == x {
						a = x
						b = y
					}
				}
			}

			if a != -1 {
				break
			}
		}

		if a != -1 {
			delete(alive, a)
			delete(alive, b)
			flag = true
		}

		if !flag && target == -1 {
			break
		}
	}

	if len(alive) == 0 {
		fmt.Println("SUCCESS")
	} else {
		fmt.Println(len(alive))
	}
}
相关推荐
无限码力1 天前
拼多多笔试真题-对角线遍历矩阵(C++/Py/Java /Js/Go)
矩阵·拼多多·拼多多笔试真题·拼多多技术岗笔试题目·拼多多机试
27669582921 年前
拼多多小程序 anti_content 分析
java·javascript·python·node·拼多多·anti-content·anti_content
27669582921 年前
拼多多 anti-token unidbg 分析
java·python·go·拼多多·pdd·pxx·anti-token
市象2 年前
独家|安克Temu平台闭店,或遭遇亚马逊“二选一”
亚马逊·temu·拼多多
诗雅颂2 年前
【js逆向学习】某多多anti_content逆向(补环境)
开发语言·javascript·webpack·逆向·拼多多·补环境·anti_content
软件、小程序、网站、脚本开发商2 年前
拼多多商品全流程自动化采集
大数据·金融·自动化·制造·零售·教育电商·拼多多
老谭聊跨境2 年前
2024年已过半,靠独立站赚钱行得通吗?
跨境电商·外贸·拼多多·独立站·海外掘金
爱python的王三金3 年前
【temu】分析拼多多跨境电商Temu数据分析数据采集
爬虫·python·数据挖掘·数据分析·跨境电商·temu·拼多多