📜  门| Gate IT 2005 |问题21(1)

📅  最后修改于: 2023-12-03 14:58:23.228000             🧑  作者: Mango

门 | Gate IT 2005 |问题21

问题描述

有N个门,每个门有一个钥匙和一个锁。钥匙和锁都有一个编号,范围从1到N。编号相同的钥匙和锁是匹配的。现在有一个人手里有N把钥匙和N把锁。但是他不知道每把钥匙和每把锁的编号,他只能尝试把所有N个钥匙插进N个锁中。当他插入某个钥匙时,他可以知道:

  1. 钥匙是否可以打开锁
  2. 如果钥匙无法打开锁,此时最近的匹配钥匙与锁的编号是多少

问:用最少的次数,匹配所有门的钥匙和锁。

解题思路

这个问题是一个匹配问题,我们可以采用匈牙利算法进行求解。

具体来说,我们可以把一个钥匙看成一个节点,把一个锁看成一个节点,然后分别将它们叫做左节点和右节点。如果一把钥匙和一把锁能够匹配,则从左节点向右节点连接一条边。

我们用一个bool类型的二维数组match记录每一对钥匙和锁是否匹配。如果第i个钥匙可以打开第j个锁,那么就有match[i][j]=true。

然后我们可以用匈牙利算法进行计算,从某个钥匙或锁开始,不断寻找其匹配的钥匙或锁,直到找到了所有的匹配为止。这个算法的时间复杂度是O(N^3)。

关于匈牙利算法的具体实现,可以参考LeetCode中这道题目的解题思路。

代码实现
bool findMatch(int i, vector<vector<bool>>& match, vector<int>& visited, vector<int>& matchResult) {
    for (int j = 0; j < match[i].size(); ++j) {
        if (match[i][j] && !visited[j]) {
            visited[j] = 1;
            if (matchResult[j] == -1 || findMatch(matchResult[j], match, visited, matchResult)) {
                matchResult[j] = i;
                return true;
            }
        }
    }
    return false;
}

int minimalTryCount(int n, vector<pair<bool,int>> keysAndLocks) {
    vector<vector<bool>> match(n, vector<bool>(n, false));
    vector<int> matchResult(n, -1);
    for (int i = 0; i < n; ++i) {
        if (keysAndLocks[i].first) {
            for (int j = 0; j < n; ++j) {
                if (keysAndLocks[j].first == false && keysAndLocks[j].second == keysAndLocks[i].second) {
                    match[i][j] = true;
                }
            }
        }
    }
    int answer = 0;
    for (int i = 0; i < n; ++i) {
        vector<int> visited(n, 0);
        if (findMatch(i, match, visited, matchResult)) {
            answer++;
        }
    }
    return n - answer;
}
参考链接

LeetCode: Matchsticks to Square