网络流24题—— 试题库问题

来源:互联网 发布:域名运营商查询 编辑:程序博客网 时间:2024/05/20 09:43

题目描述

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


输入格式

由文件input.txt提供输入数据。文件第1行有2个正整数k和n (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!”。


样例输入

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


样例输出

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


这道题,应该算是二分图匹配的变式吧?

先来试试二分图匹配的建图方法!
看做两个集合,取名无力的我选择让他们一个叫A集,一个叫B集!
A集表示需要的类型,B集表示题目

酱紫,就变成了二分图匹配的问题啦!
从A集出发有很多很多条边到B集。

用最原始的方法
假设类型一需要3道题,那么我们可以看做存在三个类型一,然后每个类型一需要一道题
对于所有的类型需要的题数都同理操作,就是正正经经的二分图匹配问题啦!

具体说说这个怎么建图:
假设,类型i需要x[i]道题目
首先,……超级源点….超级汇点
然后,把x[i]个类型i和超级源点连起来,令其容量为1
再然后,把题目和超级汇点连起来,令容量为1
接着(然后用的太多了,换个词),把类型和题目按照题目连接起来
最后,跑dinic

模仿金星老师:完美~

不过我没写过,大概会TLE?唔,无聊的时候可以写写(捂脸)
来稍微改动改动!体现网络流的优越性(雾)

咱们来把类型i的x[i]个点合并起来,令超级源点到类型i所代表的点的容量为i
然后,就跑dinic
和之前的某道题一样哟,某条边的flow==1就代表被匹配到了!
唔,顺便说一句。这样跑出来的最大流的值如果比需要的题目数量还少,就代表木有成功咯,需要输出”No Solution!”

然后就没有然后啦!和以前一样搞就可以了的说~

唔,温馨提示:注意数据范围
因为我RE了!(捂脸)


#include<cstdio>#include<vector>#include<cstring>#include<queue>#define INF 1e8using namespace std;const int maxn=1505;int n,m,s,t;struct Edge{int from,to,cap,flow;};vector<Edge>edges(20000);vector<int>G[maxn];int d[maxn];bool vis[maxn];int k;void AddEdge(int from,int to,int cap){    edges.push_back((Edge){from,to,cap,0});    edges.push_back((Edge){to,from,0,0});    k=edges.size();    G[from].push_back(k-2);    G[to].push_back(k-1);}int DFS(int x,int a){    int flow=0,f;    if(x==t || a==0) return a;    for(int i=0;i<G[x].size();i++){        Edge& e=edges[G[x][i]];        if(d[e.to]==d[x]+1 && (f=DFS(e.to,min(a,e.cap-e.flow)))>0){            e.flow+=f;            edges[G[x][i]^1].flow-=f;            a-=f;            flow+=f;            if(a==0) break;        }    }    return flow;}bool BFS(){    queue<int>q;    memset(vis,0,sizeof(vis));    d[s]=1;vis[s]=true;q.push(s);    while(!q.empty()){        int x=q.front();q.pop();        for(int i=0;i<G[x].size();i++){            Edge& e=edges[G[x][i]];            if(!vis[e.to] && e.cap>e.flow){                d[e.to]=d[x]+1;                vis[e.to]=true;                q.push(e.to);            }        }    }    return vis[t];}int dinic(){    int flow=0;    while(BFS())        flow+=DFS(s,INF);    return flow;}int main(){    int sum=0;    scanf("%d%d",&n,&m);    s=0;t=n+m+1;    for(int c,i=1;i<=n;i++){        scanf("%d",&c);        AddEdge(s,i,c);        sum+=c;    }    for(int a,k,i=1;i<=m;i++){        scanf("%d",&k);        for(int j=1;j<=k;j++){            scanf("%d",&a);            AddEdge(a,i+n,1);        }    }    for(int i=n+1;i<=m;i++) AddEdge(i,t,1);    if(dinic()!=sum){puts("No Solution!");}    else{        for(int i=1;i<=n;i++){            printf("%d:",i);            for(int j=0;j<G[i].size();j++){                Edge e=edges[G[i][j]];                if(e.to!=t && e.flow==1){                    printf(" %d",e.to-n);                }            }            printf("\n");        }    }    return 0;}
0 0