题意
题解
最大孤立点集
题意即求学生互不位于可作弊位置的最大人数,将学生看做顶点,可作弊的座位间连一条边,则问题转化为求最大孤立点集。对于二分图而言(可作弊位置间 y y y 坐标总是不相同的,所有的边都连接 y y y 为偶数和 y y y 为奇数的顶点),最大独立集等于最大二分匹配。
class Solution {
public:
static const int MAX_V = 64;
int dx[4] = {-1, 0, -1, 0};
int dy[4] = {-1, -1, 1, 1};
int V, m, n;
vector<int> G[MAX_V];
int match[MAX_V];
bool used[MAX_V];
void add_edge(int u, int v){
G[u].push_back(v);
G[v].push_back(u);
}
bool dfs(int v){
used[v] = true;
for(int i = 0; i < G[v].size(); i++){
int u = G[v][i], w = match[u];
if(w < 0 || (!used[w] && dfs(w))){
match[v] = u;
match[u] = v;
return true;
}
}
return false;
}
// 最大二分匹配
int bipartite_matching(){
int res = 0;
memset(match, -1, sizeof(match));
for(int v = 0; v < V; v++){
if(match[v] < 0){
memset(used, 0, sizeof(used));
if(dfs(v)){
++res;
}
}
}
return res;
}
void clear_graph(){
for(int v = 0; v < V; v++) G[v].clear();
}
int maxStudents(vector<vector<char>>& seats) {
clear_graph();
m = seats.size(), n = seats[0].size();
V = n * m; // 顶点值范围
int num = 0; // 可座位置数
for(int x = 0; x < m; x++){
for(int y = 0; y < n; y++){
if(seats[x][y] == '.'){
++num;
for(int i = 0; i < 4; i++){
int nx = x + dx[i], ny = y + dy[i];
if(nx >= 0 && nx < m && ny >= 0 && ny < n && seats[nx][ny] == '.'){
add_edge(x * n + y, nx * n + ny);
}
}
}
}
}
return num - bipartite_matching();
}
};
状态压缩 DP
压缩每一行的状态,通过 s & ( s > > 1 ) s\&(s>>1) s&(s>>1) 判断当前行状态是否合法(即是否有学生处于相邻位置),通过 ( s 1 & ( s 2 > > 1 ) ) ∣ ∣ ( s 1 & ( s 2 < < 1 ) ) (s1\&(s2>>1))\ ||\ (s1\&(s2<<1)) (s1&(s2>>1)) ∣∣ (s1&(s2<<1)) 判断前一行状态是否合法(即前一行是否有学生位于当前行学生左上、右上位置)。 d p [ i ] [ s ] dp[i][s] dp[i][s] 代表第 i i i 行状态为 s s s 时, 0 0 0 至 i i i 行的最大学生数。
class Solution {
public:
int n, m;
int mat[8];
int dp[8][1 << 8];
int sum(int x){
int s = 0;
while(x > 0) s += 1 & x, x >>= 1;
return s;
}
bool judge(int s1, int s2){
return (s1 & (s2 << 1)) || (s1 & (s2 >> 1));
}
int maxStudents(vector<vector<char>>& seats) {
m = seats.size(), n = seats[0].size();
for(int i = 0; i < m; i++){
int s = 0;
for(int j = 0; j < n; j++){
if(seats[i][j] == '#') s |= 1 << j;
}
mat[i] = s;
}
memset(dp, 0, sizeof(dp));
for(int s = 0; s < 1 << n; s++){
if(!(s & mat[0] || s & (s >> 1))) dp[0][s] = sum(s);
}
for(int i = 1 ; i < m; i++){
for(int s1 = 0; s1 < 1 << n; s1++){
if(s1 & mat[i] || (s1 & (s1 >> 1))) continue;
for(int s2 = 0; s2 < 1 << n; s2++){
if(!judge(s1, s2)) dp[i][s1] = max(dp[i][s1], dp[i - 1][s2]);
}
dp[i][s1] += sum(s1);
}
}
return *max_element(dp[m-1], dp[m-1]+(1 << n));
}
};