zoukankan      html  css  js  c++  java
  • 二分图多重匹配问题

    首先诚挚感谢BYvoid大神博客里提供的好题和数据 此为线性规划与网络流24题的第七题。

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

    这个题比较简单,直接建立增加原点S汇点T,建立S到题目类型的容量为需选出题数的边,题目类型到对应题目的容量为1的边,题目到T的容量为1的边,然后最大流即可。

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    const int MAXN=1e6+10;
    const int INF=~0U>>1;
    using namespace std;
    int n,k,m=0;
    int tot=0,Maxflow=0;
    int S,T;
    int h[1010],a[1010],path[1010];
    int head[1010];
    struct edge{
        int to,cap,f;
        int op,next;
    }edge[MAXN];
    void addedge(int a,int b,int c)
    {
        edge[tot].to=b;
        edge[tot].cap=c;
        edge[tot].next=head[a];
        edge[tot].op=tot^1;
        edge[tot].f=0;
        head[a]=tot++;
        edge[tot].to=a;
        edge[tot].cap=0;
        edge[tot].f=0;
        edge[tot].next=head[b];
        edge[tot].op=tot^1;
        head[b]=tot++;
    }
    void Init()
    {
        memset(head,-1,sizeof(head));
        scanf("%d%d",&k,&n);
        S=0;T=n+k+1;
        int t;
        rep(i,1,k)
        {
            scanf("%d",&t);
            addedge(S,i,t);
            m+=t;
        }
        rep(i,1,n)
        {
            int p;
            scanf("%d",&p);
            rep(j,1,p)
            {
                scanf("%d",&t);
                addedge(t,k+i,1);
            }
        }
        rep(i,k+1,n+k)
        {
            addedge(i,T,1);
        }
    }
    bool Dinic_restruct()
    {
        queue <int>q;
        memset(h,-1,sizeof(h));
        h[S]=0;q.push(S);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int j=head[u];j!=-1;j=edge[j].next)
            {
                int v=edge[j].to;
                if(h[v]==-1&&edge[j].cap-edge[j].f)
                {
                    h[v]=h[u]+1;
                    q.push(v);
                    if(v==T) return true;
                }
            }
        }
        return false;
    }
    void Dinic_augment()
    {
        int i,j,f,Stop=1;
        a[Stop]=S;
        while(Stop)
        {
            i=a[Stop];
            if(i!=T)
            {
                int v;
                for(j=head[i];j!=-1;j=edge[j].next)
                {
                    v=edge[j].to;
                    if(h[v]==h[i]+1&&edge[j].cap-edge[j].f) break;
                }
                if(j!=-1)
                {
                    a[++Stop]=v;
                    path[Stop]=j;
                }
                else
                {
                    h[i]=-1;
                    Stop--;
                }
            }
            else
            {
                f=INF;
                for(j=Stop;j>=2;--j)
                {
                    int t=path[j];
                    if(edge[t].cap-edge[t].f<f) f=edge[t].cap-edge[t].f;
                }
                Maxflow+=f;
                for(j=Stop;j>=2;--j)
                {
                    int t=path[j];
                    edge[t].f+=f;
                    edge[t^1].f-=f;
                    if(edge[t].cap-edge[t].f==0) Stop=j-1;
                }
    
            }
        }
    }
    void Dinic()
    {
        while(Dinic_restruct())
            Dinic_augment();
    }
    void Pout()
    {
        //printf("maxflow=%d m=%d",Maxflow,m);
        if(Maxflow<m) printf("No Solution!");
        else
        {
            rep(i,1,k)
            {
                printf("%d:",i);
                for(int j=head[i];j!=-1;j=edge[j].next)
                {
                    int v=edge[j].to;
                    if(v>k&&v<n+k+1&&edge[j].f) printf("%d ",v-k);
                }
                printf("
    ");
            }
        }
    }
    int main()
    {
        freopen("data3.in","r",stdin);
        Init();
        Dinic();
        Pout();
        return 0;
    }
  • 相关阅读:
    164.Maximum Gap
    163.Missing Ranges
    162.Find Peak Element
    161.One Edit Distance
    160.Intersection of Two Linked Lists
    7.5爬取猫眼Top100电影名单
    7.5文件操作
    7.4文件操作(1)
    7.4一个失败的网易云爬虫,
    7.3数据结构(1)
  • 原文地址:https://www.cnblogs.com/zhixingr/p/7157360.html
Copyright © 2011-2022 走看看