首先诚挚感谢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; }