網路流24題(七)
阿新 • • 發佈:2021-10-03
網路流24題(七)
七、試題庫問題
題目描述
問題描述:
假設一個試題庫中有 \(n\) 道試題。每道試題都標明瞭所屬類別。同一道題可能有多個類別屬性。現要從題庫中抽取 \(m\) 道題組成試卷。並要求試卷包含指定型別的試題。試設計一個滿足要求的組卷演算法。
程式設計任務:
對於給定的組卷要求,計算滿足要求的組卷方案。
輸入格式
第一行有兩個正整數 \(k\) 和 \(n\)。\(k\) 表示題庫中試題型別總數,\(n\) 表示題庫中試題總數。
第二行有 \(k\) 個正整數,第 i$$ 個正整數表示要選出的型別 \(i\) 的題數。這 \(k\) 個數相加就是要選出的總題數 \(m\)
接下來的 \(n\) 行給出了題庫中每個試題的型別資訊。每行的第一個正整數 \(p\) 表明該題可以屬於 \(p\) 類,接著的 \(p\) 個數是該題所屬的型別號。
輸出格式
輸出共 \(k\) 行,第 \(i\) 行輸出 i:
後接型別 \(i\) 的題號。
如果有多個滿足要求的方案,只要輸出一個方案。
如果問題無解,則輸出No Solution!
。
題解
模型:
最大流,二分圖匹配
建圖與實現:
和二分圖匹配差不多,不一樣的僅僅只有右集合(\(k\)集合),這個集合與匯點連線的時候邊的容量不再是1而是題目給出的常數。\(wa\)了一發是因為前向星為空的時候不會直接跳過,要特判一下。
程式碼
#include<bits/stdc++.h> using namespace std; #define ll int const ll N = 2050,M = 2e5+5,inf = 0x3f3f3f3f; ll head[N],cnt = 1; struct Edge{ll to,w,nxt;}edge[M]; void add(ll u,ll v,ll w){ edge[++cnt].to = v; edge[cnt].w = w; edge[cnt].nxt = head[u]; head[u] = cnt; } ll n,m = 0,k,s,t,lv[N],cur[N]; bool bfs(){ memset(lv, -1, sizeof(lv)); lv[s] = 0; memcpy(cur, head, sizeof(head)); queue<int> q;q.push(s); while (!q.empty()){ int p = q.front();q.pop(); for (ll eg = head[p]; eg; eg = edge[eg].nxt){ ll to = edge[eg].to, vol = edge[eg].w; if (vol > 0 && lv[to] == -1)lv[to] = lv[p] + 1, q.push(to); } } return lv[t] != -1; } ll dfs(ll p = s, ll flow = inf){ if (p == t)return flow; ll rmn = flow; for (ll &eg = cur[p]; eg; eg = edge[eg].nxt){ if (!rmn)break; ll to = edge[eg].to, vol = edge[eg].w; if (vol > 0 && lv[to] == lv[p] + 1){ ll c = dfs(to, min(vol, rmn)); rmn -= c; edge[eg].w -= c; edge[eg ^ 1].w += c; } } return flow - rmn; } ll dinic(){ ll ans = 0; while(bfs()) ans += dfs(); return ans; } ll num[N]; vector<ll> vec[N]; int main(){ ios::sync_with_stdio(false); cin>>k>>n; for(ll i = 1;i <= k;i++)cin>>num[i],m+=num[i]; for(ll i = 1;i <= n;i++){ ll p;cin>>p; while(p--){ ll x;cin>>x; add(x,i+k,1); add(i+k,x,0); } } s = 0,t = n+k+1; for(ll i = 1;i <= k;i++){ add(s,i,num[i]); add(i,s,0); } for(ll i = k+1;i <= k+n;i++){ add(i,t,1); add(t,i,0); } ll flow = dinic(); if(flow == m){ for(ll i = 1;i <= k;i++){ cout<<i<<": "; for(ll j = head[i];j;j = edge[j].nxt){ if(edge[j].to == 0) continue; if(edge[j].w == 0) cout<<edge[j].to-k<<' '; } cout<<endl; } }else puts("No Solution!"); return 0; }