P2763试题库问题(二分图匹配+匈牙利)
作者:互联网
题目描述:
问题描述:
假设一个试题库中有 n 道试题。每道试题都标明了所属类别。同一道题可能有多个类别属性。现要从题库中抽取 m 道题组成试卷。并要求试卷包含指定类型的试题。试设计一个满足要求的组卷算法。
编程任务:
对于给定的组卷要求,计算满足要求的组卷方案。
输入格式
第一行有两个正整数 k 和 n。k 表示题库中试题类型总数,n 表示题库中试题总数。
第二行有 k个正整数,第 ii 个正整数表示要选出的类型 i 的题数。这 k 个数相加就是要选出的总题数 m。
接下来的 n 行给出了题库中每个试题的类型信息。每行的第一个正整数 p 表明该题可以属于 p 类,接着的 p 个数是该题所属的类型号。
思路:二分图匹配,不过这次匹配的个数不是一个,而是多个,而且还要输出结果,还是照搬匈牙利
算法,匹配满了就从头再找替换点。
AC代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 100005; const int inf = 0x3f3f3f3f; struct edge { int f, t, nxt; }e[maxn]; int hd[maxn], tot = 1; void add(int f, int t) { e[++tot] = { f,t,hd[f] }; hd[f] = tot; } int now[maxn], match[30][maxn], need[maxn]; bool vis[maxn]; bool dfs(int u) { for (int i = hd[u]; i; i = e[i].nxt) { int v = e[i].t; if (vis[v])continue; vis[v] = 1; if (now[v]!=need[v]) {//如果还没满,就直接放 now[v]++; match[v][now[v]] = u; return true; } for (int j = 1; j <= now[v]; j++) {//找替换点 if (dfs(match[v][j])) { match[v][j] = u; return true; } } } return false; } int k, n; int main() { //freopen("test.txt", "r", stdin); scanf("%d%d", &k, &n); for (int i = 1; i <= k; i++) { scanf("%d", &need[i]); } for (int i = 1; i <= n; i++) { int num; scanf("%d", &num); for (int j = 1; j <= num; j++) { int p; scanf("%d", &p); add(i, p); } } for (int i = 1; i <= n; i++) { memset(vis, 0, sizeof(vis)); dfs(i); } bool f = 1; for (int i = 1; i <= k; i++) {//判断是否全部放满 if (now[i] != need[i]) { f = 0; break; } } if (f) {//打印结果 for (int i = 1; i <= k; i++) { printf("%d:", i); for (int j = 1; j <= need[i]; j++) { printf(" %d", match[i][j]); } printf("\n"); } } else { printf("No Solution!\n"); } return 0; }
标签:二分,试题库,int,maxn,题库,P2763,now,hd,试题 来源: https://www.cnblogs.com/MYMYACMer/p/14651475.html