liberOJ#6006. 「网络流 24 题」试题库 网络流, 输出方案

#6006. 「网络流 24 题」试题库

 
 

题目描述

假设一个试题库中有 n nn 道试题。每道试题都标明了所属类别。同一道题可能有多个类别属性。现要从题库中抽取 m mm 道题组成试卷。并要求试卷包含指定类型的试题。试设计一个满足要求的组卷算法。

输入格式

第 1 11 行有 2 22 个正整数 k kk 和 n nn。k kk 表示题库中试题类型总数,n nn 表示题库中试题总数。第 2 22 行有 k kk 个正整数,第 i ii 个正整数表示要选出的类型 i ii 的题数。这 k kk 个数相加就是要选出的总题数 m mm。

接下来的 n nn 行给出了题库中每个试题的类型信息。每行的第 1 11 个正整数 p pp 表明该题可以属于 p pp 类,接着的 p pp 个数是该题所属的类型号。

输出格式

第 i ii 行输出 i: 后接类型 i ii 的题号。如果有多个满足要求的方案,只要输出一个方案。如果问题无解,则输出 No Solution!

样例

样例输入

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 6 8
2: 7 9 10
3: 2 3 4 5

数据范围与提示

2≤k≤20,k≤n≤1000 2 \leq k \leq 20, k \leq n \leq 10002k20,kn1000

 

题解:

  wannafly题解

  建立二分图,每个类别为X集合中的顶点,每个题为Y集合中的顶点,增设附加源S和汇T。

  1、从S向每个Xi连接一条容量为该类别所需数量的有向边。
  2、从每个Yi向T连接一条容量为1的有向边。
  3、如果一个题i属于一个类别j,连接一条从Xj到Yi容量为1的有向边。

  求网络最大流,如果最大流量等于所有类别所需之和,则存在解,否则无解。对于每个类别,从X集合对应点出发的所有满流边,指向的B集合中的顶点就是该类别的所选的题(一个可行解)。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,double>
#define MP make_pair
typedef long long LL;
typedef unsigned long long ULL;
const long long INF = 1e18+1LL;
const double pi = acos(-1.0);
const int N = 1e5+10, M = 1e3+20,inf = 2e9;

int head[N],t=2,h[N],q[N],S,T,ans = 0;
struct edge{int to,next,v;}e[N * 2];
void adds(int u,int v,int w)
 {e[t].to=v;e[t].v=w;e[t].next=head[u];head[u]=t++;}
void add(int u,int v,int w) {adds(u,v,w);adds(v,u,0);}
int bfs() {
    memset(h,-1,sizeof(h));
    int l=0,r=1,now;
    q[l]=S;
    h[S]=0;
    while(l!=r){
        now=q[l++];if(l == 100000) l=0;
        for(int i=head[now];i!=-1;i=e[i].next) {
            if(e[i].v&&h[e[i].to]==-1) {
                h[e[i].to]=h[now]+1;
                q[r++]=e[i].to;
                if(r==100000) r = 0;
            }
        }
    }
    if(h[T]==-1) return 0;
    else return 1;
}
int dfs(int x,int f) {
        if(x == T) return f;
        int used=0,w;
        for(int i=head[x]; i!=-1;i=e[i].next) {
            if(e[i].v&&h[e[i].to] == h[x] + 1) {
                w=dfs(e[i].to,min(f-used,e[i].v));
                used+=w;e[i].v-=w;e[i^1].v+=w;
                if(used == f) return f;
            }
        }
        return used;
}
void dinic() {while(bfs()) ans+=dfs(S,inf);}

int k,n,a[N];
vector<int  >G[N];
int main() {
    scanf("%d%d",&k,&n);S = 2*(n+k)+1,T = S+1;
    t = 2;memset(head,-1,sizeof(head));
    int sum = 0;
    for(int i = 1; i <= k; ++i) {
        scanf("%d",&a[i]);
        add(S,i,a[i]);
        sum += a[i];
    }
    for(int i = 1; i <= n; ++i) {
        int x,y;
        scanf("%d",&x);
        for(int j = 1; j <= x; ++j) {
            scanf("%d",&y);
            add(y,i+k,1);
        }
        add(i+k,T,1);
    }
    ans = 0;
    dinic();
    if(ans != sum) puts("No Solution!");
    else {
        for(int i = 1; i <= k; ++i) {
            printf("%d:",i);
            for(int j = head[i]; j!=-1; j = e[j].next) {
                if(e[j].v == 0 && e[j].to!=S) {
                    printf(" %d",e[j].to - k);
                }
            }
            printf("\n");
        }
    }
    return 0;
}

 

 

posted @ 2017-07-28 15:46  meekyan  阅读(485)  评论(0编辑  收藏  举报