寻找生成N对唯一的无冲突课程对的方法的数量

问题描述

我遇到了这个问题,无法想到一个好的解决方案。问题如下

有N项CS课程和N项EEE课程,都编号为1,2,...,N。

对于每个i,j(1≤i,j≤N),CS路线i和EEE路线j的相容性以整数Aij给出。如果Aij = 1,则CS路线i和EEE路线j不冲突;如果Aij = 0,则会发生冲突。

Ravan正在尝试制作N对,每对包含不冲突的CS路线和EEE路线。在这里,每个CS课程和每个EEE课程都必须完全属于一对。

找到Ravan可以制作N对的模数,取模10 ^ 9 + 7。

Ex.

0 1 1
1 0 1
1 1 1

res : 3
Explanation 
Here there are 3 ways to make pairs:

(1,2),(2,1),(3,3)

(1,3),1)

(1,2)

Where (i,j) is pair of CS i course and EEE j course

为解决上述问题,我编写了一个简单的dfs函数,但这似乎是不正确的。而且这是一个非常慢的实现。我的方法如下:

int counter=0;

void dfs(vector<vector<int>>&nums,int n,vector<bool>&visit,int c){
    
    if(c == n-1){
        counter++;
        return;
    }
    
    for(int i=0; i<n; i++){
        if(nums[i][c]==0 || visit[i])continue;
        visit[i] = true;
        dfs(nums,n,visit,c+1);
        visit[i] = false;
    }
    
}

void solve(vector<vector<int>>&nums,int n){
    vector<bool>visit(n,false);
    dfs(nums,0);
    cout << counter%1000000007;
}

我在为这个问题的正确方向思考吗?还有什么可以解决这个问题的呢?任何帮助都是有价值的。谢谢!

解决方法

这只是@amit注释的扩展,看起来像是包含-排除。

首先,我们采用多种方法制作N对。这就是N!。在您的示例中,该值为6。

all sets of pairs
(1,1),(2,2),(3,3)
(1,3),2)
(1,1)
(1,1)

然后,对于不需要的每对,我们减去制作N对(包括禁止对)的方法数量。此类对的数量乘以(N-1)!。在您的示例中,该数字为4。(2对,每对分为两组N对。)

Contains forbidden pair (1,2)

Contains forbidden pair (2,1)

但是制作N对(包括2对禁止对)的方式现在已被减去两次。 (也就是说,我们将(1,3)加一次,减去两次,现在以-1计数。)因此,我们需要重新添加它们。重新添加1:

Contains both forbidden pairs (1,3)

如果存在一组3个禁止对,则我们必须将其重新添加。但是没有。所以我们的最终计算结果是:

6 - (2 + 2) + 1

根据需要给出3。

那么,如何对更大的N进行此计算呢?我们知道如何计算N!(N-1)!(N-2)!等。棘手的是,有多少对禁止配对,2对,3对等等。

为此,我们可以使用动态编程。构建dp,使dp[k][l]l禁止对(i,j)的集合数,这些集合可以一起出现在i <= k的分配中。我们从dp[0] = [1,...]开始。 dp[N]会为您提供所有可以分配给每个大小的禁止对对的计数。

在您的示例中,该结构应该结束:

dp = [
    [1,0],[1,1,2,]

我们从中获得计算结果

3! * dp[3][0] - 2! * dp[3][1] + 1! * dp[3][2] + 0! * dp[3][3]
  = 6 * 1 - 2 * 2 + 1 * 1 - 1 * 0
  = 3

那足以让你前进。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...