• 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

    //感觉做此题最大的障碍就是看不下题面去233
    //开一个超级源点,向每种试卷类型连边,边权为这种类型需要的试卷数量
    //然后试卷类型向试卷连边,边权为1
    //试卷向超级汇点连边,边权为1 
    
    //怎么输出方案。。。
    //emmmmm.......想想 
    //枚举每种试卷类型,看看与它相连的试卷的边的边权==0?
    //......试一下 

    //OK,过了
    #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<string> #include<algorithm> #include<queue> using namespace std; inline int read() { char c=getchar();int num=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num; } const int N=1e4+5; int k,n,sum,S,T; int head[N],num_edge; struct Edge { int v,flow,nxt; }edge[N]; inline void add_edge(int u,int v,int flow) { edge[++num_edge].v=v; edge[num_edge].flow=flow; edge[num_edge].nxt=head[u]; head[u]=num_edge; } int dep[N],from[N]; bool bfs() { queue<int> que; que.push(S); for(int i=S;i<=T;++i) from[i]=head[i],dep[i]=0; dep[S]=1; int now,v; while(!que.empty()) { now=que.front(),que.pop(); for(int i=head[now];i;i=edge[i].nxt) { v=edge[i].v; if(!dep[v]&&edge[i].flow) { dep[v]=dep[now]+1; if(v==T) return 1; que.push(v); } } } return 0; } int dfs(int u,int flow) { if(u==T||!flow) return flow; int outflow=0,tmp; for(int i=head[u],v;i;i=edge[i].nxt) { v=edge[i].v; if(dep[v]!=dep[u]+1||!edge[i].flow) continue; tmp=dfs(v,min(flow,edge[i].flow)); if(!tmp) continue; edge[i].flow-=tmp; edge[i^1].flow+=tmp; flow-=tmp; outflow+=tmp; if(!flow) return outflow; } dep[u]=-1; return outflow; } int paper[20][N]; int main() { num_edge=1; k=read(),n=read(); for(int i=1,x;i<=k;++i) { x=read(),sum+=x; add_edge(S,i,x); add_edge(i,S,0); } T=sum+n+1; for(int i=sum+1,p,x;i<=n+sum;++i) { p=read(); while(p--) { x=read(); add_edge(x,i,1); add_edge(i,x,0); } add_edge(i,T,1); add_edge(T,i,0); } int ans=0; while(bfs()) { ans+=dfs(S,0x7fffffff); } if(ans!=sum) puts("No Solution!"); else { for(int A=1;A<=k;++A) { for(int i=head[A],v;i;i=edge[i].nxt) { v=edge[i].v; if(v==S) continue; if(!edge[i].flow) paper[A][++paper[0][A]]=v-sum; } } for(int i=1;i<=k;++i) { printf("%d: ",i); for(int j=1;j<=paper[0][i];++j) { printf("%d ",paper[i][j]); } puts(""); } } return 0; }
  • 相关阅读:
    堆排序
    2019晋城一中开放日
    严格次小生成树
    遥远的国度
    noip2018游记
    Luogu1736 创意吃鱼法
    P3958 奶酪
    Luogu3385 负环
    Luogu1040 加分二叉树
    Luogu1007 独木桥
  • 原文地址:https://www.cnblogs.com/lovewhy/p/9031191.html
Copyright © 2020-2023  润新知