【洛谷】试题库问题-网络流

xiaoxiao2021-03-01  31

传送门:洛谷-试题库问题


题意

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


输入

第1行有2个正整数k和n (2 <=k<= 20, k<=n<= 1000) k 表示题库中试题类型总数,n 表示题库中试题总数。第2 行有k 个正整数,第i 个正整数表示要选出的类型i的题数。这k个数相加就是要选出的总题数m。接下来的n行给出了题库中每个试题的类型信息。每行的第1 个正整数p表明该题可以属于p类,接着的p个数是该题所属的类型号。


输出

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


题解

    网络流建模问题。     我们先建立一个源点和一个汇点。     然后在每个类型号与源点之间连一条容量为要求题数的有向边。     对于每一道题,我们在该题与对应类型号之间连一条容量为1的有向边,并在该题与汇点之间也连一条容量为1的有向边。     接着跑最大流,一定要源点出发的每条边都流满了才有解。


代码

#include<cstdio> #include<cstring> #include<iostream> #include<cstdlib> #include<queue> #define INF 0x7fffffff using namespace std; const int N=2e6+10; int t[22],head[N],to[N],nxt[N],w[N],flow[N]; int d[N],n,k,cnt,T=2e5,dir[N],vis[1002]; queue<int>Q; inline int read() { char ch=getchar();int x=0,t=1; while(ch>'9' || ch<'0') {if(ch=='-') t=-1;ch=getchar();} while(ch>='0' && ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*t; } inline void link(int u,int v,int cap) { to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;w[cnt]=cap; } inline bool bfs() { memset(d,-1,sizeof(d)); d[0]=0;Q.push(0); while(!Q.empty()){ int now=Q.front();Q.pop(); for(int i=head[now];i;i=nxt[i]){ if(d[to[i]]==-1 && w[i]>flow[i]){ d[to[i]]=d[now]+1; Q.push(to[i]); } } } if(d[T]==-1) return false; return true; } inline int min(int x,int y) { return x>y? y:x; } inline int dfs(int st,int ed,int f) { if(st==ed) return f; int tot=0; for(int i=head[st];i;i=nxt[i]){ if(d[to[i]]==d[st]+1 && w[i]>flow[i]){ int ww=f-tot; int qw=dfs(to[i],ed,min(w[i],ww)); if(qw>0){ flow[i]+=qw; flow[i^1]-=qw; tot+=qw; if(tot==f) return tot; } } } if(tot==0) d[st]=-1; return tot; } inline void solve() { while(bfs()) dfs(0,T,INF); } inline bool check() { for(int i=head[0];i;i=nxt[i]){ if(w[i]!=flow[i]) return false; } return true; } inline void print() { for(int i=1;i<=k;i++){ printf("%d: ",i); for(int j=head[i];j && t[i];j=nxt[j]){ if(!vis[to[j]]){ t[i]--; vis[to[j]]=1; printf("%d ",to[j]-k); } } printf("\n"); } } int main(){ k=read();n=read(); for(int i=1;i<=k;i++){ t[i]=read();link(0,i,t[i]);link(i,0,0); } for(int i=1;i<=n;i++){ int op=read(); while(op--){ int in=read(); link(in,k+i,1);link(k+i,in,0); link(k+i,T,1);link(T,k+i,0); } } solve(); if(!check()){ printf("No Solution!\n"); return 0; } print(); return 0; }
转载请注明原文地址: https://www.6miu.com/read-3450130.html

最新回复(0)