【网络流24题】试题库问题

来源:互联网 发布:有关网络得现代诗歌 编辑:程序博客网 时间:2024/05/19 23:26

Description

假设一个试题库中有 n道试题。每道试题都标明了所属类别。同一道题可能有多个类别属性。现要从题库中抽取 m道题组成试卷。并要求试卷包含指定类型的试题。试设计一个满足要求的组卷算法。

对于给定的组卷要求,计算满足要求的组卷方案。

Input

文件第 1行有 2个正整数 k和n(2≤k≤20,k≤n≤1000),k表示题库中试题类型总数, n表示题库中试题总数。

第 2行有 k个正整数,第i个正整数表示要选出的类型 i的题数。这k个数相加就是要选出的总题数m。

接下来的n行给出了题库中每个试题的类型信息。每行的第1个正整数p表明该题可以属于p类,接着的p个数是该题所属的类型号。

Output

文件第i行输出“i:”后接类型i的题号。如果有多个满足要求的方案,只要输出1个方案。如果问题无解,则输出“No Solution!”。

Sample Input

3 153 3 42 1 21 31 31 31 33 1 2 32 2 32 1 31 21 22 1 22 1 32 1 21 13 1 2 3

Sample Output

1: 1 6 82: 7 9 103: 2 3 4 5
题解

网络流最大流

1.从每种题目类型向汇点连接一条容量为每种题目所需要的数目的边。
2.从原点向每道试题连接一条容量为1的边。
3.从每道试题向每种它所属的类型连接一条容量为1的边。

跑一遍最大流,如果最大流小于m,那么没有方案,输出方案的话就是随便搞一搞就可以了。

code
#include <queue>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define debug(...) fprintf(stderr,__VA_ARGS__)#define N 1010#define T 1001#define inf 0x7fffffffusing namespace std;struct node{    int next,to,s;};node Edge[N*N*2];int n,k,m,tot=1;int used[25];int head[N];int h[N];void add(int x,int y,int z){    Edge[++tot].next=head[x];    Edge[tot].to=y;    Edge[tot].s=z;    head[x]=tot;}void ins(int x,int y,int z){    add(x,y,z),add(y,x,0);}bool bfs(){    queue<int>Q;    Q.push(0);    memset(h,-1,sizeof(h));    h[0]=0;    while(!Q.empty())    {        int u=Q.front();        Q.pop();        for(int i=head[u];i;i=Edge[i].next)        {            int to=Edge[i].to,s=Edge[i].s;            if(!s||h[to]!=-1)continue;            h[to]=h[u]+1;            Q.push(to);        }    }    if(h[T]==-1)return false;    return true;}int dfs(int u,int f){    if(u==T)return f;    int used=0;    for(int i=head[u];i;i=Edge[i].next)    {        int to=Edge[i].to,s=Edge[i].s;        if(!s||h[to]!=h[u]+1)continue;        int w=f-used;        w=dfs(to,min(w,s));        used+=w;        Edge[i].s-=w;        Edge[i^1].s+=w;        if(used==f)return f;    }    if(!used)h[u]=-1;    return used;}int dinic(){    int ans=0;    while(bfs())        ans+=dfs(0,inf);    return ans;}void getans(){    for(int i=n+1;i<=n+k;i++)    {        printf("%d:",i-n);        for(int j=head[i];j;j=Edge[j].next)        {            if(Edge[j].to==T||!Edge[j].s)continue;            printf(" %d",Edge[j].to);        }        puts("");    }}int main(){    cin>>k>>n;    for(int x,i=1;i<=k;i++)    {        scanf("%d",&x);        ins(i+n,T,x);        m+=x;    }    for(int x,y,i=1;i<=n;i++)    {        ins(0,i,1);        scanf("%d",&x);        while(x--)        {            scanf("%d",&y);            ins(i,y+n,1);        }    }    int tmp=dinic();    debug("%d\n",tmp);    if(tmp<m){puts("No Solution!");return 0;}    getans();    return 0;}
0 0
原创粉丝点击