牛客练习赛61 C 四个选项(查并集+dfs)

链接:https://ac.nowcoder.com/acm/contest/5026/C

题目描述

众所周知,高考数学中有一个题目是给出12个单项选择,每一个选择的答案是 A,B,C,D 中的一个。
网上盛传答案存在某种规律,使得蒙对的可能性大大增加。于是今年老师想让你安排这12个题的答案。但是他有一些条件,首先四个选项的数量必须分别为 na,nb,nc,nd。其次有 m 个额外条件,分别给出两个数字 x,y,代表第 x 个题和第 y 个题的答案相同。 现在你的老师想知道,有多少种可行的方案安排答案。

输入描述:

第一行五个非负整数na,nb,nc,nd,m,保证na+nb+nc+nd=12,0≤m≤1000。
接下来m行每行两个整数x,y(1≤ x,y ≤12)代表第x个题和第y个题答案必须一样。

输出描述:

仅一行一个整数,代表可行的方案数。
示例1
输入
3 3 3 3 0
输出
369600

思路:

可以把ABCD看成四个桶,12个选项放进去,问有多少种不同放法?若选项答案一样则绑在一起(同一个父节点)。用查并集捆绑和dfs遍历就行了。

代码:

#include <bits/stdc++.h>
using namespace std;
int n[5],nx[5]={
    
    0},m;
long long ans=0;
int f[15],vis[15]={
    
    0};
int aa=0,bb=0,cc=0,dd=0;
int a,b,c,d;
inline int find(int x)
{
    
    
	while(f[x]!=x)
	x=f[x]=f[f[x]];
	return x;
}
void dfs(int x)
{
    
    
	if(x==13)
	{
    
    
		ans++;
		return ;
	}
	if(vis[x]==0)
	dfs(x+1);
	else
	{
    
    
		for(int i=1;i<=4;i++)
		{
    
    
			if(nx[i]+vis[x]<=n[i])//nx[]是当前选项的数量 
			{
    
    
				nx[i]+=vis[x];
				dfs(x+1);
				nx[i]-=vis[x];
			}
		}
	}
}
int main()//a,b,c,d四个篮子,十二选项投进去 
{
    
    
	cin>>n[1]>>n[2]>>n[3]>>n[4]>>m;//n[]是选项的最大数量 
	for(int i=1;i<=12;i++)
	f[i]=i;
	int x,y,fa,fb;
	for(int i=1;i<=m;i++)
	{
    
    
		cin>>x>>y;
    	fa=find(x);fb=find(y);
    	if(fa!=fb)
   	 	{
    
    	
        	f[fb]=fa;
    	}
	}
	for(int i=1;i<=12;i++)
	vis[find(i)]++;//vis[]存储有多少个选项是相互独立的 
	dfs(1);
	cout<<ans;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xiaolan7777777/article/details/105498414