链接: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;
}