【網絡流24題-洛谷-P2763】試題庫問題(二分圖多重匹配)

題目描述

«問題描述:

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

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: 1 6 8
2: 7 9 10
3: 2 3 4 5

ac代碼:

二分圖多重匹配,首先起點到類型點連邊流量爲a[i],然後每個試題和他所屬的類型以及終點連邊,流量爲1。輸出路徑,只要便利每個流量點的出邊看看流量是否爲0,還要排除反向邊。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<vector>
#include<bitset>
#include<time.h> 
using namespace std;
typedef long long ll;
struct node{
	int u,v,nxt,w;	
}e[100005<<1];
int tot=1,head[10050];//tot從1開始,雙向邊異或
int st,ed;
int dis[10050],q[10050];
void add(int u,int v,int w){
	e[++tot].v=v;
	e[tot].u=u;
	e[tot].w=w;
	e[tot].nxt=head[u];
	head[u]=tot;
}
int bfs(int st,int ed){
	memset(dis,-1,sizeof(dis));
	int front=0,tail=0;
	q[tail++]=st;
	dis[st]=0;
	while(front<tail){
		int cur=q[front++];
		if(cur==ed) return 1;
		for(int i=head[cur];i!=-1;i=e[i].nxt){
			if(e[i].w&&dis[e[i].v]<0){
				q[tail++]=e[i].v;
				dis[e[i].v]=dis[cur]+1;
			}
		}
	}
	if(dis[ed]==-1) return 0;
	return 1;
}
int dfs(int cur,int lim){
	if(lim==0||cur==ed) return lim;
	int w,flow=0;
	for(int i=head[cur];i!=-1;i=e[i].nxt){
		if(e[i].w&&dis[e[i].v]==dis[cur]+1){
			w=dfs(e[i].v,min(lim,e[i].w));
			e[i].w-=w;
			e[i^1].w+=w;
			flow+=w;
			lim-=w;
			if(lim==0) break;
		}
	}
	if(!flow) dis[cur]=-1;
	return flow;
}
int dinic(){
	int ans=0;
	while(bfs(st,ed)) 
		ans+=dfs(st,0x7fffffff);
	return ans;
}
int main(){
	int k,n,w,num,m=0;
	scanf("%d%d",&k,&n);
	for(int i=0;i<=n+k+5;i++) head[i]=-1;
	for(int i=1;i<=k;i++){
		scanf("%d",&w);
		m+=w;
		add(st,i,w);
		add(i,st,0);
	}
	for(int i=1;i<=n;i++){
		scanf("%d",&num);
		for(int j=1;j<=num;j++){
			scanf("%d",&w);
			add(w,k+i,1);
			add(k+i,w,0);
		}
	}
	ed=n+k+1;
	for(int i=1;i<=n;i++){
		add(k+i,ed,1);
		add(ed,k+i,0);
	}
	int tmp=dinic();
	if(tmp==m){
		for(int i=1;i<=k;i++){
			printf("%d:",i);
			for(int j=head[i];j!=-1;j=e[j].nxt){
				if(e[j].w==0&&e[j].v>e[j].u){//注意去除反向邊
					printf(" %d",e[j].v-k);
				}
			}
			puts("");
		}
	}
	else puts("No Solution!");
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章