LeetCode 1349. The maximum number of students test (like pressure or DP bipartite graph maximum independent subset) is determined bipartite graph (cross-staining) Maximum bipartite graph matching (Hungarian Algorithm)

Give you a m * n matrix representation seats in a classroom seats distribution. If the seat is bad (not available), use '#' indicates; otherwise, denoted by '.'.

Students can see on the left, right, upper left, upper right next to the four directions of his students answer, but students can not see him sitting directly in front of or behind the answer. Please work and returns the maximum number of students taking the exam together and can not cheat the examination room can hold.

Students must be in good condition sitting on the seat.

Example 1:

输入:seats = [["#",".","#","#",".","#"],
              [".","#","#","#","#","."],
              ["#",".","#","#",".","#"]]
Output: 4 
to explain: Teachers can allow 4 students sitting in seats available, so they can not cheat in exams.

prompt

seats only character ' . ' and ' # ' 
m == seats.length
n == seats[i].length
1 <= m <= 8
1 <= n <= 8

 

1. DP-shaped pressure

First, a look at the data range, a learned man like pressure DP should think of it ...... personal experience, when the next data range of around 10, you can consider is not like pressure DP.

With every binary enumeration to a sitting position whether people, and his party have n seats, 1 << n is a kind of total cases.

DP [i] [j] for the i-th row j is the maximum state, then dp [i] [j] = j + max 1 state includes the number of (dp [i-1] [k]) (0 <= k <(1 << n) && j and k are legal status && j and k are not capable of two positions of each copy is present)

When the game code is written in relatively ugly writing more than 80 lines ...... a bit after the game reference solution to a problem, use j & (j << 1) to determine whether there is an adjacent point is more powerful -

AC Code (cpp)

class Solution {
    int countOne(int x) {
        int cnt = 0;
        while(x != 0) x = x & (x - 1), cnt++;
        return cnt;
    }
public:
    int maxStudents(vector<vector<char>>& seats) {
        int n = seats.size();
        int m = seats[0].size();
        int st = 1 << m;

        vector<vector<int>> dp(n, vector<int>(st, 0));
        for (int i = 0; i < n; i++) {
            int mask = 0;
            for (int j = 0; j < m; j++) {
                mask += seats[i][j] == '#' ? (1 << j) : 0;
            }
            for (int j = 0; j < st; j++) {
                if (!(j & mask) && !(j & (j << 1))) {
                    int v = countOne(j);
                    if (i == 0) dp[i][j] = v;
                    else {
                        for (int k = 0; k < st; k++) {
                            if (!((k << 1) & j) && !((k >> 1) & j)) {
                                dp[i][j] = max(dp[i][j], dp[i - 1][k] + v);
                            }
                        }
                    }
                }
            }
        }
        int ans = 0;
        for (int i = 0; i < st; i++) {
            ans = max(dp[n - 1][i], ans);
        }

        return ans;
    }
};

 

2. bipartite graph maximum matching

Too long without written bipartite graph has no impression, prompted by the group where big God, that she reviewed again before the blog.

Analyzing bipartite graph (cross-staining)

Maximum bipartite graph matching (Hungarian Algorithm)

 

If this question can copy each of two connection positions, seeking the maximum number of candidates that can be accommodated without seeking the maximum internal set of edges, i.e., the maximum independent subset.

At the same time we know bipartite graph properties 

= The maximum number of independent vertex number - the maximum number of matches

Then converted for the sake of this question bipartite graph maximum matching.

 

One thing to note is that the template Hungary, is a case of two separate set points go on seeking the most matches, and is similar to this question does not specify which set of points which belong point,

Therefore, every conceivable point split into the two points, each point belonging to a subset, this is the result corresponding to the maximum matching algorithm.

As for the original collection, the answer should be the maximum matching / 2.

 

AC Code (cpp)

class Solution {
    static const int N = 64;
    vector<int> G[N];
    bool used[N];
    int match[N];
    int r, c, n;
    int id(int row, int col) {
        return row * c + col;
    }
    void join(int x, int y) {
        G[x].push_back(y);
        G[y].push_back(x);
    }
    bool findPath(int u) {
        for (int v: G[u]) {
            if (used[v]) continue;
            used[v] = true;
            if (match[v] == -1 || findPath(match[v])) {
                match[v] = u;
                return true;
            }
        }
        return false;
    }
public:
    int maxStudents(vector<vector<char>>& seats) {
        r = seats.size(), c = seats[0].size(), n = r * c;
        int total = 0;

        for (int i = 0; i < r; i++) {
            for (int j = 0; j < c; j++) {
                if (seats[i][j] == '.') {
                    total++;
                    if (i > 0) {
                        if (j > 0 && seats[i - 1][j - 1] == '.') { // 左上
                            join(id(i, j), id(i - 1, j - 1));
                        }
                        if (j + 1 < c && seats[i - 1][j + 1] == '.') { // 右上
                            join(id(i, j), id(i - 1, j + 1));
                        }
                    }
                    if (j > 0 && seats[i][j - 1] == '.') { // 左侧
                        join(id(i, j), id(i, j - 1));
                    }
                }
            }
        }
        int matchNum = 0 ;
        memset(match, -1, sizeof match);
        for (int i = 0; i < n; i++) {
            memset(used, false, sizeof used);
            if (findPath(i)) ++matchNum;
        }

        return total - matchNum / 2;
    }
};

 

Guess you like

Origin www.cnblogs.com/wenruo/p/12357543.html