假設一個試題庫中有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!”。
輸入示例: 輸出示例:
3 15 1: 1 6 8
3 3 4 2: 7 9 10
2 1 2 3: 2 3 4 5
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
分析:
這題有點水,二分圖多重匹配。所有題目爲X點,所有類型爲Y點,建立源點S,匯點T
S連接所有的X點,容量爲1,表示每題只能選擇一次。所有的Y點連接T點,容量爲每個類型的需求題數。
對於每題X能屬於不同的Y的類型,就連接對應的X,Y點,容量爲1,其實這裏的容量1還是無窮都無所謂的,因爲源匯點已經限制了容量。
然後求一次最大流,如果最大流等於題目合,就有解。對於所有從X出發指向Y的邊,流量爲1則爲一個可行解。否則無解輸出No Solution!。
代碼應該也沒什麼要解釋的。
代碼:
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 1001;
const int INF = 1<<30;
struct edge{
int from,to,cap,flow;
edge(int a,int b,int c,int d):from(a),to(b),cap(c),flow(d)
{}
};
vector<int> g[maxn];
vector<edge> edges;
bool visit[maxn];
int d[maxn];
int cur[maxn];
int s,t;
void addedge(int from,int to,int cap)
{
edges.push_back(edge(from,to,cap,0));
edges.push_back(edge(to,from,0,0));
int m=edges.size();
g[from].push_back(m-2);
g[to].push_back(m-1);
}
bool BFS()
{
memset(visit,false,sizeof(visit));
d[s]=0;
queue<int> q;
q.push(s);
visit[s]=true;
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(!visit[e.to]&&e.cap>e.flow){
visit[e.to]=true;
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}
return visit[t];
}
int DFS(int x,int a)
{
if(x==t||a==0) return a;
int flow=0,f;
for(int &i=cur[x];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){
flow+=f;
a-=f;
e.flow+=f;
edges[g[x][i]^1].flow-=f;
if(a==0) break;
}
}
return flow;
}
int main()
{
int k,n;
scanf("%d%d",&k,&n);
s=0;t=k+n+1;
int cap,sum=0;
for(int i=1;i<=k;i++){
scanf("%d",&cap);
sum+=cap;
addedge(i,t,cap);
}
getchar();
for(int i=k+1;i<=k+n;i++){
int res=0,c;
while((c=getchar())!='\n'){
if(c==' ') {addedge(i,res,1);res=0;}
else res=res*10+c-'0';
}
addedge(i,res,1);
addedge(s,i,1);
}
int flow=0;
while(BFS()){
memset(cur,0,sizeof(cur));
flow+=DFS(s,INF);
}
if(flow!=sum) printf("“No Solution!\n");
else{
for(int i=1;i<=k;i++){
printf("%d:",i);
for(int j=0;j<g[i].size();j++){
edge &e=edges[g[i][j]^1];
if(e.flow==1) printf(" %d",e.from-k);
}
printf("\n");
}
}
return 0;
}