洛谷P2763 试题库问题

题目:https://www.luogu.org/problemnew/show/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

说明

感谢 @PhoenixEclipse 提供spj

解析

网络流24题之一orz。

二分图多重匹配。

每道题跟T连容量为1的边。

每类题跟S连容量为需要该类题数量的边。

每道题跟它所在的题的类别连容量为1的边。

跑最大流,如果结果小于题目总数,则无解。

否则,对每条连接题的类别和题目的边检查,

若满流,输出题目的编号即可。

至于洛谷的90分:

检查一下是否有条边连了0节点(似乎数据有问题)。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<vector>
  7 #include<queue>
  8 using namespace std;
  9 #define maxn 10000
 10 struct line{
 11     int to;
 12     int cap,flow;
 13 };
 14 vector<line> edge;
 15 vector<int> G[maxn];
 16 bool vis[maxn];
 17 int dis[maxn];
 18 int cur[maxn];
 19 int n,k,m,rep,re;
 20 int inv[maxn];
 21 int S,T;
 22 void addedge(int from,int to,int cap){
 23     edge.push_back((line){to,cap,0});
 24     edge.push_back((line){from,0,0});
 25     int sz=edge.size();
 26     G[from].push_back(sz-2);
 27     G[to].push_back(sz-1);
 28 }
 29 bool bfs(){
 30     memset(vis,false,sizeof(vis));
 31     vis[S]=true;
 32     dis[S]=0;
 33     queue<int> q;
 34     q.push(S);
 35     while (!q.empty()){
 36         int u=q.front();
 37         q.pop();
 38         for (int i=0;i<G[u].size();++i){
 39             line e=edge[G[u][i]];
 40             if (vis[e.to]) continue;
 41             if (e.flow>=e.cap) continue;
 42             vis[e.to]=true;
 43             dis[e.to]=dis[u]+1;
 44             q.push(e.to);
 45         }
 46     }
 47     return vis[T];
 48 }
 49 int dfs(int x,int a){
 50     if (a==0||x==T) return a;
 51     int f,flow=0;
 52     for (int &i=cur[x];i<G[x].size();++i){
 53         line &e=edge[G[x][i]];
 54         if (dis[e.to]==dis[x]+1&&(f=dfs(e.to,min(a,e.cap-e.flow)))){
 55             flow+=f;
 56             a-=f;
 57             e.flow+=f;
 58             edge[G[x][i]^1].flow-=f;
 59             if (!a) break;
 60         }
 61     }
 62     return flow;
 63 }
 64 int dinic(){
 65     int ans=0;
 66     while (bfs()){
 67         memset(cur,0,sizeof(cur));
 68         ans+=dfs(S,10000);
 69     }
 70     return ans;
 71 }
 72 int main(){
 73     scanf("%d%d",&k,&n);
 74     S=0; T=2*n+1;
 75     for (int i=1;i<=n;++i){
 76         addedge(i+k,T,1);
 77     }
 78     for (int i=1;i<=k;++i){
 79         scanf("%d",&inv[i]);
 80         m+=inv[i];
 81         addedge(S,i,inv[i]);
 82     }
 83     for (int i=1;i<=n;++i){
 84         scanf("%d",&rep);
 85         for (int j=1;j<=rep;++j){
 86             scanf("%d",&re);
 87             addedge(re,i+k,1);
 88         }
 89     }
 90     if (dinic()<m){
 91         printf("No Solution!");
 92         return 0;
 93     }
 94     for (int i=1;i<=k;++i){
 95         printf("%d:",i);
 96         for (int j=0;j<G[i].size();++j){
 97             line e=edge[G[i][j]];
 98             if (e.cap==e.flow&&e.to) printf(" %d",e.to-k);
 99         }
100         printf("\n");
101     }
102     return 0;
103 }

AC

90分,100分分别是这么写的:

 1 //90分:
 2     for (int i=1;i<=k;++i){
 3         printf("%d:",i);
 4         for (int j=0;j<G[i].size();++j){
 5             line e=edge[G[i][j]];
 6             if (e.cap==e.flow&&e.to!=k) printf(" %d",e.to-k);
 7         }
 8         printf("\n");
 9     }
10 //100分:
11     for (int i=1;i<=k;++i){
12         printf("%d:",i);
13         for (int j=0;j<G[i].size();++j){
14             line e=edge[G[i][j]];
15             if (e.cap==e.flow&&e.to) printf(" %d",e.to-k);
16         }
17         printf("\n");
18     }

compare

希望有大佬给更好解释orz。

时间: 2024-11-12 01:17:50

洛谷P2763 试题库问题的相关文章

P2763 试题库问题

\(\color{#0066ff}{题目描述}\) ?问题描述: 假设一个试题库中有n道试题.每道试题都标明了所属类别.同一道题可能有多个类别属性.现要从题库中抽取m 道题组成试卷.并要求试卷包含指定类型的试题.试设计一个满足要求的组卷算法. ?编程任务: 对于给定的组卷要求,计算满足要求的组卷方案. \(\color{#0066ff}{输入格式}\) 第1行有2个正整数k和n (2<=k<=20, k<=n<=1000),k 表示题库中试题类型总数,n 表示题库中试题总数. 第2

luogu P2763 试题库问题

本题可以用最大流也可以用最大匹配(本质一样),用dinic最大流好建图,但码量大,匈牙利码量小,建图费点劲. 最大流:依旧是设一个源点一个汇点,对于每一个种类,连一条到汇点的边,capacity为需要的量,对于每一个试题,从源点连一条capacity为1的边到他,从他对每一个其所属的编号种类连一条capacity为1的边,求最大流即可,再找出最小割即可 #include<bits/stdc++.h> using namespace std; #define lowbit(x) ((x)&

【题解】Luogu P2763 试题库问题

原题传送门 这题很简单啊 从源点向k类题目分别连流量为所需数量的边 从每道题向汇点连一条流量为1的边(每题只能用1次) 从类型向对应的题目连一条流量为1的边 跑一边最大流 如果最大流小于所需题目数量,就无解 否则对于每个类型,看每道题是否要选 #include <bits/stdc++.h> #define inf 0x3f3f3f3f #define M 80005 #define N 2005 //#define getchar nc using namespace std; inline

洛谷 P2709 BZOJ 3781 小B的询问

题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表示第i个询问的答案. 输入输出样例 输入样例#1: 6 4 3 1 3 2 1 1 3

洛谷1231 教辅的组成

洛谷1231 教辅的组成 https://www.luogu.org/problem/show?pid=1231 题目背景 滚粗了的HansBug在收拾旧语文书,然而他发现了什么奇妙的东西. 题目描述 蒟蒻HansBug在一本语文书里面发现了一本答案,然而他却明明记得这书应该还包含一份练习题.然而出现在他眼前的书多得数不胜数,其中有书,有答案,有练习册.已知一个完整的书册均应该包含且仅包含一本书.一本练习册和一份答案,然而现在全都乱做了一团.许多书上面的字迹都已经模糊了,然而HansBug还是可

洛谷教主花园dp

洛谷-教主的花园-动态规划 题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价值. 教主最喜欢3种树,这3种树的高度分别为10,20,30.教主希望这一圈树种得有层次感,所以任何一个位置的树要比它相邻的两棵树的高度都高或者都低,并且在此条件下,教主想要你设计出一套方案,使得观赏价值之和最高. 输入输出格式 输入格式: 输入文件garden.in的第1行为一个正整数n,表示需要种的

洛谷 P2801 教主的魔法 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=2801 题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的身高一开始都是不超过1000的正整数.教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W.(虽然L=R时并不

洛谷P1466 集合 Subset Sums

洛谷P1466 集合 Subset Sums这题可以看成是背包问题 用空间为 1--n 的物品恰好填充总空间一半的空间 有几种方案 01 背包问题 1.注意因为两个交换一下算同一种方案,所以最终 要 f [ v ] / 2 2.要开 long long 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string&g

洛谷P1160 队列安排 链表

洛谷P1160 队列安排   链表 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <cstdlib> 5 #include <string> 6 #include <algorithm> 7 #include <iomanip> 8 #include <iostream> 9 using namespace std