zoukankan      html  css  js  c++  java
  • 1301 任务分配

    1301 任务分配

     

    2003年浙江省队选拔赛

     时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 大师 Master
     
     
    题目描述 Description

    有N位工作人员,同时有N项任务, 每人必须承担一项任务,若给出某人不能从事的某些任务, 问要安排好工作,共有多少种方案?

    输入描述 Input Description

    输入文件第1行为N(1<=N<=100), 以下N行,其中第i+1行表示第i个人不能从事的任务编号, 任务之间用空隔分开, 若第i个人没有限制条件,则第i+1行为空行, 所有人员不能从事的任务之和不大于25。

    输出描述 Output Description

    输出文件只有1行,为所有满足条件的分配方案数。

    样例输入 Sample Input

      4

      2

      2 3

      3 4

      4

    样例输出 Sample Output

    4

    数据范围及提示 Data Size & Hint

    如题

    分类标签 Tags 点此展开 

     

    分析

    容斥原理的应用.

    先看看样例:
    四个人: A, B, C, D

    A 不能选择: 2
    B 不能选择: 2 3
    C 不能选择: 3 4
    D 不能选择: 4

    总数是1~4全排列的个数 => 4! = 24
    再考虑不能选的情况
    那么
    =>

    采用 总数-非法个数 的方法计算, 而后者需用容斥原理计算.
    answer :
    = 4! - (|非法A + 非法B + 非法C + 非法D|)
    = 4! - {|非法A| + |非法B| + |非法C| + |非法D| - |非法AB| - |非法AC| - |非法AD| - |非法BC| - |非法BD| - |非法CD| + |非法ABC| + |非法ABD| + |非法ACD| + |非法BCD| - |非法ABCD|}
    = 4! - 3! - 2 * 3! - 2 * 3! - 3! + 2! + 2 * 2! + 2! + 3 * 2! + 2 * 2! + 2! - 1 - 1 - 1 - 1 + 0
    = 4

    容斥的实现

    据说有三种实现容斥原理的方法 :
    1. dfs
    2. 队列数组
    3. 二进制

    只学了dfs法.
    核心是统计各个阶乘的系数(coe), 记录在数组里, 最后高精统计.

    根据 answer 的计算式子, 可以发现 : |P1 并 … Pm| m为奇数时, (n-m)! 的系数是负的. 容斥原理里这里是正的, 但别忘这里前头还有负号.

    感觉这个dfs怪怪的… 先递归到底层, 又边回溯边更改.

    变量表.
    main() :
    fac: 阶乘
    cnt: 限制关系的个数
    x[]: 人物
    y[]: 任务
    x[] <==> y[] // 一一对应

    dfs() :
    // 时间复杂度: O(2^15 = 32768)
    coe[] 统计各个阶乘被计算了多少次
    cur: 当前不匹配关系的编号
    visx: 此人以考虑过
    visy: 此任务已有人做
    num: 当前正在统计 n-num 的阶乘的出现次数
    |A1并A2并…并Anum|
    num 为偶数 => coe[n-num]++
    num 为奇数 => coe[n-num]–-

    来自:http://blog.csdn.net/qq_21110267/article/details/43882591

    AC代码:

    #include <cstdio>
    #include <string>
    #include <cstring>
    #include <iostream>
    #include <sstream>
    using namespace std;
    const int maxn=100+10;
    struct bigint{
        static const int base=10000;
        int n,a[base];
        bigint operator += (const bigint& x){
            n=max(n,x.n)+1;
            for(int i=0;i<n;i++){
                a[i]+=x.a[i];
                a[i+1]+=a[i]/base;
                a[i] %= base;
            }
            while(n>0&&a[n-1]==0) n--;
            return *this;
        }
        bigint operator -= (const bigint& x){
            for(int i=0;i<n;i++){
                if(a[i]<x.a[i]){
                    a[i]+=base;
                    a[i+1]-=1;
                }
                a[i]-=x.a[i];
            }
            while(n>0&&a[n-1]==0) n--;
            return *this;
        }
        bigint operator * (const int& x){
            bigint ans;
            ans.n=n+1;
            memset(ans.a,0,sizeof(ans.a));
            int rest=0;
            for(int i=0;i<ans.n;i++){
                ans.a[i]=a[i] * x+rest;
                rest=ans.a[i]/base;
                ans.a[i]%=base;
            }
            while(ans.n>0&&ans.a[ans.n-1]==0) ans.n--;
            return ans;
        }
        void print(){
            printf("%d",a[n-1]);
            for(int i=n-2;i>=0;i--) printf("%04d",a[i]);
            printf("
    ");
        }
    };
    int n,cnt,x[maxn],y[maxn],coe[maxn];
    bool visx[maxn],visy[maxn];
    bigint ans,fac[maxn];
    // 当前正在考虑第 cur 对不匹配关系
    // 正在计算 |A1 并 A2 并 ... 并 Anum|
    void dfs(int cur,int num){
        if(cur>cnt){
            coe[n-num]+=(num&1)?-1:1;
            return ;
        } 
        dfs(cur+1,num);
        if(!visx[x[cur]]&&!visy[y[cur]]){
            visx[x[cur]]=visy[y[cur]]=1;
            dfs(cur+1,num+1);
            visx[x[cur]]=visy[y[cur]]=0;
        }
    }
    int main(){
        cin>>n;
        fac[0]=(bigint){1,{1}};
        for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i;
        string tmp;
        getline(cin,tmp);
        for(int i=0,j;i<n;i++){
            string readline;// 不要定义在循环外,因为如果没有读入readline,会自动保留上次结果. 
            getline(cin,readline);
            stringstream ss(readline);
            while(ss>>j){
                cnt++;
                x[cnt]=i;
                y[cnt]=j;
            }
        }
        dfs(1,0);
        // 统计
        for(int i=0;i<=n;i++) if(coe[i]>0) ans+=fac[i]*coe[i];
        for(int i=0;i<=n;i++) if(coe[i]<0) ans-=fac[i]*(-coe[i]);
        ans.print();
        return 0;
    }
  • 相关阅读:
    数组去重
    css盒模型
    px、em、rem的区别
    Html5新标签
    弹性布局
    相对定位与绝对定位
    Hadoop综合大作业
    分布式文件系统HDFS 练习
    安装Hadoop
    爬虫综合大作业
  • 原文地址:https://www.cnblogs.com/shenben/p/6053384.html
Copyright © 2011-2022 走看看