题目链接
链接: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
思路:真是汗颜呀,训练是练的越来越难了,但结果这个C还卡了好久,居然顿时最简单的爆搜也不会搞了,卡了好久QAQ。直接将同分数的用并查集合并,剩下点就是爆搜了。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int father[13],vis[13],a,b,c,d,m,aa=0,bb=0,cc=0,dd=0,ans=0;
int findfather(int x)
{
if(x==father[x]) return x;
int i=findfather(father[x]);
father[x]=i;
return i;
}
void unit(int x,int y)
{
int fa=findfather(x),fb=findfather(y);
if(fa!=fb)
{
father[fa]=fb;
}
}
void dfs(int x)
{
if(x==13) {
ans++;return ;
}
if(vis[x]==0) dfs(x+1);
else{
if(aa+vis[x]<=a) aa+=vis[x],dfs(x+1),aa-=vis[x];
if(bb+vis[x]<=b) bb+=vis[x],dfs(x+1),bb-=vis[x];
if(cc+vis[x]<=c) cc+=vis[x],dfs(x+1),cc-=vis[x];
if(dd+vis[x]<=d) dd+=vis[x],dfs(x+1),dd-=vis[x];
}
}
int main()
{
scanf("%d %d %d %d %d",&a,&b,&c,&d,&m);
for(int i=0;i<=12;++i) father[i]=i;
for(int i=1,x,y;i<=m;++i) {
scanf("%d %d",&x,&y);
unit(x,y);
}
for(int i=1;i<=12;++i) vis[findfather(i)]++;
dfs(1);
cout<<ans<<endl;
}