背景
快要期中考试了!老师需要hzy帮他排考试的座位。。。
描述
考场里的座位恰好有n行m列,并且恰好有n*m位考生在这个考场里面考试,也就是说,所有的座位上都有考生。hzy根据学校记载,有k位考生可能作弊,因此hzy不能让他们之中的任何两个人做在相邻的座位上!所谓相邻的座位,即在同一行相邻列或者在同一列的相邻行的座位。hzy准备这样安排座位,首先随机选择一种方案,如果这种方案是合法的,就用这种方案,否则重新选择。你的任务是计算,他得到一个合法方案时,需要的期望选择次数。
格式
输入格式
输入文件为一行,仅包含三个整数n,m和k。
输出格式
如果不存在合法的方案,则输出文件seating.out中应该包含Impossible!,否则输出一个分数p/q,表示期望选择次数(即平均次数),这里p和q应该是互质的。
提示
1≤n≤80,1≤m≤80,1≤n*m≤80
0≤k≤20,并且k≤n*m
对于题目状态压缩很明显,然后是对于组合数,组合数是我的弱点,高中知识基本都忘得差不多了
提示一下:C(m,n) = n!/(m! * (n - m)!) -> n*(n-1)*(n-2)....(n-m+1)/m!(这里的k比较小,所以这么转换,如果是n-m比较小则可以转换为:n*(n-1)*(n-2).....*(m+1)/(n-m)!)
如此其他的就是状态压缩的过程了
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
LL dp[80 + 5][20 + 5][1 << 12];
int n, m, k;
LL gcd(LL a,LL b) {
return b? gcd(b, a % b) : a;
}
bool C(int mm,int s) {
for(int i = 0; i < 15; i ++) {
if((s & (1 << i)) && (mm & (1 << i))) return false;
}
return true;
}
bool CC(int s) {
int bits[15] = {0},cnt = 0;
while(s) {
bits[cnt ++] = (s & 1);
s >>= 1;
}
for(int i = 1; i < cnt; i ++) {
if(bits[i] + bits[i - 1] >= 2)return false;
}
return true;
}
LL CS(LL c, LL s) {
LL ret = 1;
for(int i = 1; i <= s; i ++) ret = ret * (c - i + 1) / i;
return ret;
}
void CSS(LL nn,LL kk,LL x) {
LL xi = 1,sh = 1,f;
for(int i = 1; i <= kk; i ++) xi *= i;
for(int i = nn - kk + 1; i <= nn; i ++ ) {
sh *= i;
f = gcd(sh,xi);
sh /= f;
xi /= f;
}
xi *= x;
f = gcd(xi,sh);
xi /= f;
sh /= f;
printf("%I64d/%I64d\n",sh,xi);
}
int main() {
scanf("%d%d%d", &n, &m, &k);
if(m > n) swap(n, m);
dp[0][0][0] = 1;//第几行安排了多少人了,以及此时要安装的人数
for(int i = 1; i <= n; i ++) {
for (int j = 0; j <= k; j ++) {
for(int s = 0; s < (1 << m); s ++) {
if(!CC(s)) continue;
int bits = 0,ft = s;
while(ft) {
bits += (ft & 1);
ft >>= 1;
}
for(int ks = 0 ; ks < (1 << m); ks ++) {
if(!CC(ks)) continue;
if(!C(ks,s)) continue;
if(j - bits < 0) continue;
dp[i][j][s] += dp[i - 1][j - bits][ks];
}
}
}
}
LL ret = 0;
for(int i = 0; i < (1 << m); i ++) {
ret += dp[n][k][i];
}
if(ret <= 0) {
printf("Impossible!\n");
} else {
CSS(n * m, k, ret);
}
return 0;
}
python代码:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
def gcd(a, b):
if not b:
return a
else:
return gcd(b, a % b)
def bit(x):
ret = 0
while x > 0:
ret += (x & 1)
x >>= 1
return ret
def C(n, k):
ret = 1
for i in range(1, k + 1): ret = ret * (n - i + 1) / i
return ret
def Is_Clear(m):
old = 0
while m > 0 :
t = m & 1
if t == 1 and old == 1:
return False
m >>= 1
old = t
return True
def Is_Conflict(m, s, n):
for i in range(n + 1):
t = 1 << i
if ((s & t) and (m & t)): return True
return False
def Get_Result(n, k, x):
S = 1
X = 1
f = 0
for i in range(1, k + 1): X *= i
for i in range(n - k + 1, n + 1):
S *= i
f = gcd(S, X)
S /= f
X /= f
X *= x
f = gcd(X, S)
X /= f
S /= f
print '%d/%d' % (S, X)
n, m, k = map(int,raw_input().split())
if n < m:
t = n
n = m
m = t
dp = []
L = []
for i in range(1 << m):
if Is_Clear(i) : L.append(i)
cnt = len(L)
for i in range(2):
a = []
for j in range(k + 1):
b = []
for f in range(cnt):
b.append(0)
a.append(b)
dp.append(a)
dp[0][0][0] = 1
index = 0
for i in range(1,n + 1):
index = not index
for j in range(k + 1):
for s in range(cnt):
dp[index][j][s] = 0
bits = bit(L[s])
for olds in range(cnt):
if Is_Conflict(L[olds], L[s], m): continue
if j - bits < 0 : continue
dp[index][j][s] += dp[not index][j - bits][olds]
ret = 0
for i in range(cnt):
ret += dp[index][k][i]
if ret <= 0 :
print 'Impossible!'
else:
Get_Result(n * m, k , ret)