码迷,mamicode.com
首页 > 编程语言 > 详细

vijos - P1286座位安排 (DP状态压缩 + 组合数 + python)

时间:2015-08-16 23:07:20      阅读:358      评论:0      收藏:0      [点我收藏+]

标签:

P1286座位安排

背景

快要期中考试了!老师需要hzy帮他排考试的座位。。。

描述

考场里的座位恰好有n行m列,并且恰好有n*m位考生在这个考场里面考试,也就是说,所有的座位上都有考生。hzy根据学校记载,有k位考生可能作弊,因此hzy不能让他们之中的任何两个人做在相邻的座位上!所谓相邻的座位,即在同一行相邻列或者在同一列的相邻行的座位。hzy准备这样安排座位,首先随机选择一种方案,如果这种方案是合法的,就用这种方案,否则重新选择。你的任务是计算,他得到一个合法方案时,需要的期望选择次数。

格式

输入格式

输入文件为一行,仅包含三个整数n,m和k。

输出格式

如果不存在合法的方案,则输出文件seating.out中应该包含Impossible!,否则输出一个分数p/q,表示期望选择次数(即平均次数),这里p和q应该是互质的。

样例1

样例输入1[复制]

1 4 3

样例输出1[复制]

Impossible!

样例2

样例输入2[复制]

2 3 2

样例输出2[复制]

15/8

提示

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;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

vijos - P1286座位安排 (DP状态压缩 + 组合数 + python)

标签:

原文地址:http://blog.csdn.net/qq_18661257/article/details/47707977

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!