【容斥+java】SGU 476 Coach's Trouble
题意:有3*n个人,分成n组,每组三个人。给出k个三元组,这三个人不可组队,问最后可以组队的总方案数
思路:
当k=0时,有(C[3*n][3]*C[3*n-3][3]*……*C[3][3])/n!种方案,展开以后可以得到dp[n]=(3*n)!/n!/6^n。
显然可以写成递推式:dp[n]=dp[n-1]*(3*n-1)*(3*n-2)/2。
那么容斥一下,答案=总方案数-至少含一个禁止组合的+至少含两个禁止组合的-……
二进制暴力TLE了。DFS的话会有很多剪枝,当前几个已经出现冲突,自然不会再往后面搜了
代码:
import java.util.*; import java.math.*; public class Solution { static int group[][] = new int[25][3]; static int cnt[] = new int[25]; static boolean vis[] = new boolean[3001]; static int n, k, depth; static void Init() { for (int i = 0; i < 25; i++) cnt[i] = 0; for (int i = 0; i < 3001; i++) vis[i] = false; } static void DFS(int index, int now) { if (now == depth) { if (depth % 2 == 1) cnt[depth]++; else cnt[depth]--; } else { for (int i = index; i < k; i++) { if (vis[group[i][0]] == false && vis[group[i][1]] == false && vis[group[i][2]] == false) { vis[group[i][0]] = vis[group[i][1]] = vis[group[i][2]] = true; DFS(i + 1, now + 1); vis[group[i][0]] = vis[group[i][1]] = vis[group[i][2]] = false; } } } } public static void main(String[] args) { Scanner in = new Scanner(System.in); BigInteger dp[] = new BigInteger[1001]; BigInteger res; dp[0] = dp[1] = BigInteger.ONE; for (int i = 2; i < 1001; i++) dp[i] = dp[i - 1].multiply(BigInteger.valueOf(3 * i - 1)) .multiply(BigInteger.valueOf(3 * i - 2)) .divide(BigInteger.valueOf(2)); while (in.hasNext()) { Init(); n = in.nextInt(); k = in.nextInt(); for (int i = 0; i < k; i++) for (int j = 0; j < 3; j++) group[i][j] = in.nextInt(); for (depth = 1; depth <= k; depth++) DFS(0, 0); res = BigInteger.ZERO; for (int i = 1; i <= k; i++) if (cnt[i] != 0) res = res.add(dp[n - i].multiply(BigInteger.valueOf(cnt[i]))); System.out.println(dp[n].subtract(res)); } } }