網路流24題—— 試題庫問題
題目描述
假設一個試題庫中有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 1e8
using 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;
}