leetcode 第四天

1.参加考试的最大学生数

给你一个 m * n 的矩阵 seats 表示教室中的座位分布。如果座位是坏的(不可用),就用 ‘#’ 表示;否则,用 ‘.’ 表示。
学生可以看到左侧、右侧、左上、右上这四个方向上紧邻他的学生的答卷,但是看不到直接坐在他前面或者后面的学生的答卷。请你计算并返回该考场可以容纳的一起参加考试且无法作弊的最大学生人数。
学生必须坐在状况良好的座位上。
在这里插入图片描述
示例 1:
输入:seats = [["#",".","#","#",".","#"],
[".","#","#","#","#","."],
["#",".","#","#",".","#"]]
输出:4
解释:教师可以让 4 个学生坐在可用的座位上,这样他们就无法在考试中作弊。

示例 2:
输入:seats = [[".","#"],
["#","#"],
["#","."],
["#","#"],
[".","#"]]
输出:3
解释:让所有学生坐在可用的座位上。

示例 3:
输入:seats = [["#",".",".",".","#"],
[".","#",".","#","."],
[".",".","#",".","."],
[".","#",".","#","."],
["#",".",".",".","#"]]
输出:10
解释:让学生坐在第 1、3 和 5 列的可用座位上。
提示:

seats 只包含字符 ‘.’ 和’#’
m == seats.length
n == seats[i].length
1 <= m <= 8
1 <= n <= 8

来源:力扣(LeetCode)

解题思路:动态规划
凡求最优化问题都可以用动态规划解决

状态转移方程: dp[i][j]=max(dp[i][j],dp[i][k]+counts[k])
边界状态:dp[0][j]=0

dp[i][j]表示到第i行为止第j中状态下能坐下的最大人数,counts(k)表示第k种状态下,当前行坐的人数
假如每行有8个座位,那么可以用一个8位的位数组来表示这八个座位的状态,0表示没人,1表示有人,则满足题目要求的当前行应该是每个座位的左右都没有人,并且每个座位的左上和右上都没有人,这里可以利用位与运算来表示
此题参考Pumpkin的解法

class Solution {
public:
    int maxStudents(vector<vector<char> >& seats) {
        int m=seats.size(),n=seats[0].size();
        //dp数组,存储第i行第j种状态下的座位数
        vector<vector<int> > dp(m+1,vector<int>(1<<n));
        //从第一行开始,第零行为边界值
        for(int row=1;row<=m;row++){
        	//每行有2^n种状态
            for(int s=0;s<(1<<n);s++){
            	//这里用位数组存储当前状态当前行座位分布情况
                bitset<8> bs(s);
                bool ok=true;
                for(int j=0;j<n;j++){
                	//判断当前座位分布是否包含坏座位,以及是否左右位置有座位
                    if((bs[j]&&seats[row-1][j]=='#')||(j<n-1&&bs[j]&&bs[j+1])){
                        ok=false;
                        break;
                    }
                }
                //不满足条件
                if(!ok){
                    dp[row][s]=-1;
                    continue;
                }
                //遍历在上层状态下,当前状态的最大座位数
                for(int last=0;last<(1<<n);last++){
                    if(dp[row-1][last]==-1){
                        continue;
                    }
                    bitset<8> lbs(last);
                    bool flag = true;
                    for(int k=0;k<n;k++){
                    	//如果左上或右上有座位,则不满足条件
                        if(lbs[k]&&((k>0&&bs[k-1])||(k<n-1&&bs[k+1]))){
                            flag = false;
                            break;
                        }
                    }
                    if(flag){
                    //状态转移方程,求出最大的座位数
                        dp[row][s]=max(dp[row][s],dp[row-1][last]+(int)bs.count());
                    }
                }
            }
        }
        int rst = 0;
        for(int i=0;i<(1<<n);i++){
            rst = max(dp[m][i],rst);
        }
        return rst;
    }
};

[注] 解答此题时,完全不知道从哪里下手,我考虑的角度是拿出单个座位来思考,而正确的思考方式应该是以行为单位或者列为单位进行考虑,而且此题我没有想到用动态规划來解,其实最优化问题都是应该联想到用动态规划来做的。此外,用位数组来表示当前座位的分布情况实在巧妙,并且状态转移方程dp[i][j]中的j就是隐含的座位信息,这个太强了,学习学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值