zoukankan      html  css  js  c++  java
  • 洛谷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("
    ");
    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("
    ");
     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("
    ");
    18     }
    compare

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

  • 相关阅读:
    软件工程实践2017第一次作业
    第七次作业
    图结构练习——最短路径(floyd算法(弗洛伊德))
    图结构练习——最短路径(dijkstra算法(迪杰斯拉特))
    图结构练习——最小生成树(kruskal算法(克鲁斯卡尔))
    图结构练习——最小生成树(prim算法(普里姆))
    基于邻接矩阵的深度优先搜索遍历
    基于邻接表的深度优先搜索遍历
    数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历
    数据结构实验之图论二:基于邻接表的广度优先搜索遍历
  • 原文地址:https://www.cnblogs.com/gjc1124646822/p/8053295.html
Copyright © 2011-2022 走看看