糖尿病康复,内容丰富有趣,生活中的好帮手!
糖尿病康复 > 洛谷P2763 试题库问题

洛谷P2763 试题库问题

时间:2019-12-10 18:26:54

相关推荐

洛谷P2763 试题库问题

题目:/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 153 3 42 1 21 31 31 31 33 1 2 32 2 32 1 31 21 22 1 22 1 32 1 21 13 1 2 3

输出样例#1:

1: 1 6 82: 7 9 103: 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{ 11int to; 12int 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){ 23edge.push_back((line){to,cap,0}); 24edge.push_back((line){from,0,0}); 25int sz=edge.size(); 26G[from].push_back(sz-2); 27G[to].push_back(sz-1); 28 } 29 bool bfs(){ 30memset(vis,false,sizeof(vis)); 31vis[S]=true; 32dis[S]=0; 33queue<int> q; 34q.push(S); 35while (!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} 47return vis[T]; 48 } 49 int dfs(int x,int a){ 50if (a==0||x==T) return a; 51int f,flow=0; 52for (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} 62return flow; 63 } 64 int dinic(){ 65int ans=0; 66while (bfs()){ 67 memset(cur,0,sizeof(cur)); 68 ans+=dfs(S,10000); 69} 70return ans; 71 } 72 int main(){ 73scanf("%d%d",&k,&n); 74S=0; T=2*n+1; 75for (int i=1;i<=n;++i){ 76 addedge(i+k,T,1); 77} 78for (int i=1;i<=k;++i){ 79 scanf("%d",&inv[i]); 80 m+=inv[i]; 81 addedge(S,i,inv[i]); 82} 83for (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} 90if (dinic()<m){ 91 printf("No Solution!"); 92 return 0; 93} 94for (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}102return 0;103 }

AC

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

1 //90分: 2for (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分:11for (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。

如果觉得《洛谷P2763 试题库问题》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。