1. 程式人生 > >【洛谷】試題庫問題-網路流

【洛谷】試題庫問題-網路流

題意

假設一個試題庫中有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; }