二分图多重匹配问题

首先诚挚感谢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("\n");
        }
    }
}
int main()
{
    freopen("data3.in","r",stdin);
    Init();
    Dinic();
    Pout();
    return 0;
}

 

posted on 2017-07-12 19:47  缄默火  阅读(680)  评论(0编辑  收藏  举报

导航