时空限制1000ms / 128MB
题目描述
«问题描述:
假设一个试题库中有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!”。
输入输出样例
最大流。
虽然点数很多,但是每条边的流量很小,这样增广次数也不会很多,用dinic可以过。(而且dinic也很难达到上界复杂度,通常一千左右的点,就算是完全图,如果边权很小的话,dinic也跑的飞快)。
#include<bits/stdc++.h> #define N 1035 using namespace std; typedef struct { int v; long long flow; } ss; ss edg[N*N]; vector<int>edges[N]; int now_edges=0; void addedge(int u,int v,long long flow) { edges[u].push_back(now_edges); edg[now_edges++]=(ss) { v,flow }; edges[v].push_back(now_edges); edg[now_edges++]=(ss) { u,0 }; } int S,T,current[N]; int dis[N]= {0}; int bfs() { memset(dis,0,sizeof(dis)); dis[S]=0; queue<int>q; q.push(S); while(!q.empty()) { int now=q.front(); q.pop(); int Size=edges[now].size(); for(int i=0; i<Size; i++) { ss e=edg[edges[now][i]]; if(e.flow>0&&dis[e.v]==0) { dis[e.v]=dis[now]+1; q.push(e.v); } } } return dis[T]; } long long dfs(int now,long long maxflow) { if(now==T)return maxflow; int Size=edges[now].size(); for(int i=current[now]; i<Size; i++) { current[now]=i; ss &e=edg[edges[now][i]]; if(e.flow>0&&dis[e.v]==dis[now]+1) { long long flow=dfs(e.v,min(e.flow,maxflow)); if(flow!=0) { e.flow-=flow; edg[edges[now][i]^1].flow+=flow; return flow; } } } return 0; } long long dinic() { long long ans=0,flow; while(bfs()) { memset(current,0,sizeof(current)); while(flow=dfs(S,LLONG_MAX/2))ans+=flow; } return ans; } int main() { int k,n; long long tot=0; scanf("%d %d",&k,&n); S=n+k+1; T=S+1; for(int i=1; i<=k; i++) { int a; scanf("%d",&a); tot+=a; addedge(n+i,T,a); } for(int i=1; i<=n; i++) { int a,p; scanf("%d",&p); while(p--) { scanf("%d",&a); addedge(i,n+a,1); } addedge(S,i,1); } long long ans=dinic(); if(ans==tot) { for(int i=1; i<=k; i++) { printf("%d:",i); int Size=edges[n+i].size(); for(int j=0; j<Size; j++) if(edg[edges[n+i][j]].flow>0)printf(" %d",edg[edges[n+i][j]].v); printf(" "); } } else printf("No Solution! "); return 0; }