• 732. [网络流24题] 试题库 二分图多重匹配/最大流


    «问题描述:
    假设一个试题库中有n道试题。每道试题都标明了所属类别。同一道题可能有多个类别属性。现要从题库中抽取m 道题组成试卷。并要求试卷包含指定类型的试题。试设计一个满足要求的组卷算法。
    «编程任务:
    对于给定的组卷要求,计算满足要求的组卷方案。
    «数据输入:
    由文件testlib.in提供输入数据。文件第1行有2个正整数k和n (2 <=k<= 20, k<=n<= 1000)k 表示题库中试题类型总数,n 表示题库中试题总数。第2 行有k 个正整数,第i 个正整数表示要选出的类型i 的题数。这k个数相加就是要选出的总题数m。接下来的n行给出了题库中每个试题的类型信息。每行的第1 个正整数p表明该题可以属于p类,接着的p个数是该题所属的类型号。
    «结果输出:
    程序运行结束时,将组卷方案输出到文件testlib.out 中。文件第i 行输出 “i:”后接类型i的题号。如果有多个满足要求的方案,只要输出1 个方案。如果问题无解,则输出“NoSolution!”。
    输入文件示例
    testlib.in
    3 15
    3 3 4
    2 1 2
    1 3
    1 3
    1 3
    1 3
    3 1 2 3
    2 2 3
    2 1 3
    1 2
    1 2
    2 1 2
    2 1 3
    2 1 2
    1 1
    3 1 2 3

    输出文件示例

    testlib.out

    1: 1 6 8
    2: 7 9 10
    3: 2 3 4 5

    【问题分析】

    二分图多重匹配问题,用最大流解决。

    【建模方法】

    建立二分图,每个类别为X集合中的顶点,每个题为Y集合中的顶点,增设附加源S和汇T。

    1、从S向每个Xi连接一条容量为该类别所需数量的有向边。
    2、从每个Yi向T连接一条容量为1的有向边。
    3、如果一个题i属于一个类别j,连接一条从Xj到Yi容量为1的有向边。

    求网络最大流,如果最大流量等于所有类别所需之和,则存在解,否则无解。对于每个类别,从X集合对应点出发的所有满流边,指向的B集合中的顶点就是该类别的所选的题(一个可行解)。

    【建模分析】

    二分图多重匹配问题。X,Y集合之间的边容量全部是1,保证两个点只能匹配一次,源汇的连边限制了每个点匹配的个数。求出网络最大流,如果流量等于X集合所有点与S边容量之和,那么则说明X集合每个点都有完备的多重匹配。

    /* 
     * Problem: 线性规划与网络流24题 #7 试题库问题
     * Author: Guo Jiabao
     * Time: 2009.6.27 16:33
     * State: Solved
     * Memo: 网络最大流 二分图多重匹配
    */
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    using namespace std;
    const int MAXN=1030,MAXM=1000*20*2+MAXN*2,INF=~0U>>1;
    struct edge
    {
        edge *next,*op;
        int t,c;
    }*V[MAXN],*P[MAXN],ES[MAXM],*Stae[MAXN];
    int N,M,S,T,EC,Ans,Maxflow,Total;
    int Lv[MAXN],Stap[MAXN];
    inline void addedge(int a,int b,int c)
    {
        ES[++EC].next = V[a]; V[a]=ES+EC; V[a]->t=b; V[a]->c=c;
        ES[++EC].next = V[b]; V[b]=ES+EC; V[b]->t=a; V[b]->c=0;
        V[a]->op = V[b]; V[b]->op = V[a];
    }
    void init()
    {
        int i,j,k,c;
        freopen("data.in","r",stdin);
        freopen("data.out","w",stdout);
        scanf("%d%d",&M,&N);
        S=0; T=N+M+1;
        for (i=1;i<=M;i++)
        {
            scanf("%d",&c);
            Total += c;
            addedge(S,i,c);
        }
        for (i=1;i<=N;i++)
            addedge(i+M,T,1);
        for (i=1;i<=N;i++)
        {
            scanf("%d",&k);
            for (j=1;j<=k;j++)
            {
                scanf("%d",&c);
                addedge(c,i+M,1);
            }
        }
    }
    bool Dinic_Label()
    {
        int head,tail,i,j;
        Stap[head=tail=0]=S;
        memset(Lv,-1,sizeof(Lv));
        Lv[S]=0;
        while (head<=tail)
        {
            i=Stap[head++];
            for (edge *e=V[i];e;e=e->next)
            {
                j=e->t;
                if (e->c && Lv[j]==-1)
                {
                    Lv[j] = Lv[i]+1;
                    if (j==T)
                        return true;
                    Stap[++tail] = j;
                }
            }
        }
        return false;
    }
    void Dinic_Augment()
    {
        int i,j,delta,Stop;
        for (i=S;i<=T;i++)
            P[i] = V[i];
        Stap[Stop=1]=S;
        while (Stop)
        {
            i=Stap[Stop];
            if (i!=T)
            {
                for (;P[i];P[i]=P[i]->next)
                    if (P[i]->c && Lv[i] + 1 == Lv[j=P[i]->t])
                        break;
                if (P[i])
                {
                    Stap[++Stop] = j;
                    Stae[Stop] = P[i];
                }
                else
                    Stop--,Lv[i]=-1;
            }
            else
            {
                delta = INF;
                for (i=Stop;i>=2;i--)
                    if (Stae[i]->c < delta)
                        delta = Stae[i]->c;
                Maxflow += delta;
                for (i=Stop;i>=2;i--)
                {
                    Stae[i]->c -= delta;
                    Stae[i]->op->c += delta;
                    if (Stae[i]->c==0)
                        Stop = i-1;
                }
            }
        }
    }
    void Dinic()
    {
        while (Dinic_Label())
            Dinic_Augment();
    }
    void print()
    {
        if (Total == Maxflow)
        {
            for (int i=1;i<=M;i++)
            {
                printf("%d: ",i);
                for (edge *e=V[i];e;e=e->next)
                    if (e->c == 0 && e->t !=S)
                        printf("%d ",e->t-M);
                putchar('
    ');
            }
        }
        else
            printf("No Solution!
    ");
    }
    int main()
    {
        init();
        Dinic();
        print();
        return 0;
    }
  • 相关阅读:
    基本语法-函数
    基本语法-变量
    python+selenium2自动化------quit()和close()区别
    docker搭建bwapp漏洞测试环境
    软件测试---登录功能的测试用例
    Faker开源库构造测试数据
    selenium自动化简易测试框架总结
    ddt+unittest+HTMLTestRunner,生成测试报告时,报告中没有输出测试用例函数的描述信息
    python+selenium2自动化---PageObject模式+unittest结合实现自动化
    python+selenium2自动化---关键字驱动+unittest结合实现自动化
  • 原文地址:https://www.cnblogs.com/Aragaki/p/7554564.html
Copyright © 2020-2023  润新知