每日一题之 hiho1765 配对(状压dp)

描述
有 n 个男生和 n 个女生,第 i 的男生的能力值为 Ai,第 i 个女生的能力值为 Bi,第 i 个男生和第 j 个女生可以配对当且仅当 Ai ≤ Bj.

求有几种将他们配成 n 对男女的方案

输入
第一行一个正整数 n

第二行 n 个正整数,第 i 个正整数表示 Ai

第三行 n 个正整数,第 i 个正整数表示 Bi

有 30% 的数据满足 1 ≤ n ≤ 5

有100% 的数据满足 1 ≤ n ≤ 12,1 ≤ Ai,Bi ≤ 100

输出
输出有几种配对的方案

样例输入
3
1 2 3
3 3 1
样例输出
2

思路:

之前懂了状压dp,现在一看到数据量这么小,且每个人只用一次就想到状压dp了。我们可以用dp[k]表示所用女生的情况。k
表示女生状态 范围为 0 k 2 n 1 。女生j配对用1表示不配对用0表示。于是我们枚举男生,假设枚举到A[i],然后从大到小枚举女生配对的状态k,(从大到小是因为,每个女生只能配对一次,类似于01背包,保证后面状态只计算一次) 再看女生B[j]中哪个可以符合要求。具体条件为 (A[i] <=B[j] )且 k的第j位不是1,k的第j位为0 表示 B[j]可以和A[i]配对。那么转移方程为 d p [ k | ( 1 << j ) ] + = d p [ k ] ; 最后所有女生都配对即k的每一位都为1时就是答案

#include <cstdio>
#include <iostream>
#include <cstring>

using namespace std;

int dp[1<<13];

int main()
{
    int A[15],B[15];
    int n;
    cin >> n;
    for (int i = 0; i < n; ++i)
        cin >> A[i];
    for (int i = 0; i < n; ++i)
        cin >> B[i];

    dp[0] = 1;

    for (int i = 0; i < n; ++i) {
        for (int k = (1<<n)-1; k >= 0; --k) {  //类似于01背包 保证每个状态是由前一个状态转移过来,而不会冲突
            for (int j = 0; j < n; ++j) {
                if (A[i] <= B[j]) {
                    if ((k & (1 << j) ) == 0)
                        dp[k|(1<<j)] += dp[k];
                } 
            }
        }
    }

    cout <<dp[(1<<n)-1] << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/u014046022/article/details/81348891