1. 程式人生 > >【刷題】LOJ 6006 「網絡流 24 題」試題庫

【刷題】LOJ 6006 「網絡流 24 題」試題庫

urn std ret ble 多個 網絡流 屬性 template +=

題目描述

假設一個試題庫中有 \(n\) 道試題。每道試題都標明了所屬類別。同一道題可能有多個類別屬性。現要從題庫中抽取 \(m\) 道題組成試卷。並要求試卷包含指定類型的試題。試設計一個滿足要求的組卷算法。

輸入格式

\(1\) 行有 \(2\) 個正整數 \(k\)\(n\)\(k\) 表示題庫中試題類型總數,\(n\) 表示題庫中試題總數。第 \(2\) 行有 \(k\) 個正整數,第 \(i\) 個正整數表示要選出的類型 \(i\) 的題數。這 \(k\) 個數相加就是要選出的總題數 \(m\)

接下來的 \(n\) 行給出了題庫中每個試題的類型信息。每行的第 \(1\)

個正整數 \(p\) 表明該題可以屬於 \(p\) 類,接著的 \(p\) 個數是該題所屬的類型號。

輸出格式

\(i\) 行輸出 i: 後接類型 \(i\) 的題號。如果有多個滿足要求的方案,只要輸出一個方案。如果問題無解,則輸出 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 \leq k \leq 20, k \leq n \leq 1000\)

題解

這和圓桌聚餐問題毫無區別啊
試題和屬性分別和源點和匯點相連,屬性容量為各自的需要,試題的容量只能為 \(1\)
試題和自己的屬性相連,容量為 \(1\)
跑最大流

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=2000+10,MAXM=MAXN*MAXN+10,inf=0x3f3f3f3f;
int n,k,e=1,beg[MAXN],cur[MAXN],level[MAXN],vis[MAXN],clk,s,t,nex[MAXM<<1],to[MAXM<<1],cap[MAXM<<1],all;
std::queue<int> q;
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
    if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void insert(int x,int y,int z)
{
    to[++e]=y;
    nex[e]=beg[x];
    beg[x]=e;
    cap[e]=z;
    to[++e]=x;
    nex[e]=beg[y];
    beg[y]=e;
    cap[e]=0;
}
inline bool bfs()
{
    memset(level,0,sizeof(level));
    level[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(register int i=beg[x];i;i=nex[i])
            if(cap[i]&&!level[to[i]])level[to[i]]=level[x]+1,q.push(to[i]);
    }
    return level[t];
}
inline int dfs(int x,int maxflow)
{
    if(x==t||!maxflow)return maxflow;
    vis[x]=clk;
    int res=0;
    for(register int &i=cur[x];i;i=nex[i])
        if((vis[to[i]]^vis[x])&&cap[i]&&level[to[i]]==level[x]+1)
        {
            int f=dfs(to[i],min(maxflow,cap[i]));
            cap[i]-=f;
            cap[i^1]+=f;
            res+=f;
            maxflow-=f;
            if(!maxflow)break;
        }
    vis[x]=0;
    return res;
}
inline int Dinic()
{
    int res=0;
    while(bfs())clk++,memcpy(cur,beg,sizeof(cur)),res+=dfs(s,inf);
    return res;
}
int main()
{
    read(k);read(n);
    s=k+n+1,t=s+1;
    for(register int i=1,x;i<=k;++i)read(x),insert(s,i,x),all+=x;
    for(register int i=1;i<=n;++i)
    {
        insert(i+k,t,1);
        int m;read(m);
        for(register int j=1,x;j<=m;++j)read(x),insert(x,i+k,1);
    }
    if(Dinic()!=all)puts("No Solution!");
    else
        for(register int x=1;x<=k;++x)
        {
            printf("%d:",x);
            for(register int i=beg[x];i;i=nex[i])
                if(!cap[i]&&(i&1^1))printf(" %d",to[i]-k);
            puts("");
        }
    return 0;
}

【刷題】LOJ 6006 「網絡流 24 題」試題庫