首页 > 试题广场 >

房间安排

[编程题]房间安排
  • 热度指数:99 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

小团是旅店老板,现在有连续的N个房间(从左到右分别编号从1N),每个房间可以住一个旅客。

 

P个游客通过美团酒店业务来到小团的旅店住宿,小团的任务是想办法给他们分配房间,要求相邻的两个房间不可以同时住上旅客。(比如3号房间和4号房间相邻,你可以两个房间都不住人,也可以3号房间住一个人4号不住,也可以3号不住4号房间住一个人,但不可以3号和4号都住人)

 

对于无法找到合法的方案进行分配的情况,输出0即可。

 

方案数不对具体的游客进行区分。例如1号房间住旅客A3号房间住旅客B,和1号房间住旅客B3号房间住旅客A视为同一种方案,即分配了1号和3号房间。

 

你的任务是给出有多少种分配的方案,方案数对10000取模即可。

 

保证 0 < P < N


输入描述:

一行两个以空格分开的自然数N和P。

对于40%的数据有2 <= N <= 10

对于60%的数据有2 <= N <= 100

对于100%的数据有2 <= N <= 1000



输出描述:
一行一个正整数表示分配的方案数量。
示例1

输入

5 3

输出

1

说明

对于样例1,只有一种分配方案,分配1号房间、三号房间、五号房间,也即(1,3,5)

示例2

输入

6 3

输出

4

说明

对于样例2,有四种分配方案,分别是(1,3,5),(1,3,6),(1,4,6),(2,4,6)

动态规划求解,将房间编号为0~n-1,dp[i][j][0]dp[i][j][1]分别表示此时有j个客人,用0~i号房间对j个客人按顺序进行分配,在第 号房间未分配和分配给客人 的方案数。
首先是初始化:
    dp[0][0][0] = 1,只有0号房间,没有客人,只有不进行分配一种方案。
    dp[0][1][1] = 1,只有0号房间,有一个客人,分配0号房间给他住,不能让他没地方住,一种方案。
状态转移:
    第 号房间如果不打算分配给客人 j,那第 i-1 号房间分没分配给 都有可能
    dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1]
     号房间如果打算分配给客人 j,那第 i-1 号房间肯定不能分配给上一个客人,否则客人 和 j-1 就相邻了
    dp[i][j][1] = dp[i - 1][j - 1][0]
最后返回 dp[n-1][p][0] + dp[n-1][p][1] 即可,表示第 n-1 号房间可能分配给 也可能不分配给 p,两种情况都要考虑。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] params = br.readLine().split(" ");
        int n = Integer.parseInt(params[0]);
        int p = Integer.parseInt(params[1]);
        // dp[i][j][0]和dp[i][j][1]表示0~i号房间在第i号未房间分配出去和分配出去给j个客人的方案数
        int[][][] dp = new int[n][p + 1][2];
        dp[0][0][0] = 1;   // 0号房间不分配给客人有一种方案
        dp[0][1][1] = 1;   // 0号房间分配给一个客人有一种方案
        for(int i = 1; i < n; i++){
            for(int j = 0; j <= p; j++){
                // 第i号房间不分配给第j个客人,第i-1号房间分没分配给他都有可能
                dp[i][j][0] = (dp[i - 1][j][0] + dp[i - 1][j][1]) % 10000;
                // 第i号房间要分配给第j个客人,那第i-1号房间肯定不能分配给上一个客人
                dp[i][j][1] = j > 0? dp[i - 1][j - 1][0]: 0;
            }
        }
        System.out.println((dp[n - 1][p][0] + dp[n - 1][p][1]) % 10000);
    }
}


编辑于 2021-03-14 10:08:10 回复(0)
我真是麻了,DP总是看不出来,这次用的排列组合,看样子是规律找错了,只过了5个;
发表于 2022-09-09 21:37:04 回复(0)
这题很明显是动态规划了,将房间编号为0~n+1,定义一个二维的dp数组,dp[i][j]表示从i到n - 1的房间住j个人的方案数量。
首先要知道怎么初始化:
    这里要明确一点,房间不住人也是一种方案,因此所有j为0的位置应该初始化为1
状态转移:
    一个房间可以住人也可以不住人
  1. 第i个房间选择选择了住人 ,那么剩下的客人(j - 1)应该从第i + 2间房开始住
  2. 第i个房间选择了不住人,那么需要住的客人还是j,且应该从第i + 1间房开始住
    方案数应该为两者之和,即状态转移方程应该为dp[i][j] = (dp[i + 2][j - 1] + dp[i + 1][j])
这里有个遍历方向的问题,i应该从n - 1倒序遍历,因为i的状态依赖于i + 1和i + 2,只有先得到这两者的状态才能得出i的状态
import java.io.BufferedReader;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new java.io.InputStreamReader(System.in));
        String[] params = br.readLine().split(" ");
        br.close();
        int n = Integer.parseInt(params[0]);
        int p = Integer.parseInt(params[1]);
        // 从第i间房到n - 1间房住j人的方案数
        int[][] dp = new int[n + 2][p + 1];
        // 初始化,不住人(j = 1)也是一种方案
        for (int i = 0; i < dp.length; i++) {
            dp[i][0] = 1;
        }
        for (int i = n - 1; i >= 0; i--) {
            // j从1开始,为0的情况已经包含在初始化内
            for (int j = 1; j <= p; j++) {
                // 第i个住人   + dp[i + 2][j - 1]
                // 第i个不住人  + dp[i + 1][j]
                dp[i][j] = (dp[i + 2][j - 1] + dp[i + 1][j]) % 10000;
            }
        }
        System.out.println(dp[0][p]);
    }
}

发表于 2022-05-12 20:11:02 回复(0)