【网络流24题】试题库问题

链接

https://www.luogu.org/problemnew/show/P2763

题目大意

k 种类型和 n 个题目,每个题目会适应部分类型,一种类型可能需要多种题,一道题可能多种类型都需要,但一道题只能满足一种类型,现要求出满足出完所有类型的题目的方案

解题思路

网络流擅长于解决各种有要求的匹配,显然这道题是有条件的匹配,可以用最大流来解决。

首先建立超源点和超汇点,源点与试题相连,汇点与类型相连,对应试题与对应类型相连

现在我们来考虑边的容量

因为一道题只可以有一个,所以源点和试题的边的容量为1

同理一道题只能满足一种类型,所以试题和类型的边的容量也为1

而需要满足的类型是有多个的,所以类型与汇点的边的容量为所需类型的数量

如图是不是好看很多
这时跑最大流即可

统计方案只需找到没有被割掉的边(可能有人不懂什么是被割掉,因为最大流=最小割)。然后输出其即可,需要注意的是,输出的不能是汇点

代码

#include<cstring>
#include<cstdio>
#include<queue>
#define M 8005
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
using namespace std;int f,n,k,s,t,num[21],sum;char c;
int read()
{
    char c;f=0;
    while(c=getchar(),c<=47||c>=58);f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),c>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
    return f;
}
void write(int x){if(x>9)write(x/10);putchar(x%10+48);return;}
struct node{int next,to,w;}e[M];
int l[M],tot,d[M];
void add(int u,int v, int w)
{
    e[tot].to=v;e[tot].w=w;e[tot].next=l[u];l[u]=tot++;
    e[tot].to=u;e[tot].w=0;e[tot].next=l[v];l[v]=tot++;
    return;
}
bool bfs()
{
    memset(d,-1,sizeof(d));
    queue<int>q;
    d[s]=0;q.push(s);
    while(q.size())
    {
        int x=q.front();q.pop();
        for(int i=l[x];~i;i=e[i].next)
        {
            int y=e[i].to;
            if(e[i].w&&d[y]==-1)
            {
                d[y]=d[x]+1;
                if(y==t) return true;
                q.push(y);
            }
        }
    }
    return false;
}
int dfs(int x,int flow)
{
    if(x==t||!flow) return flow;
    int rest=0,f;
    for(int i=l[x];i!=-1;i=e[i].next)
    {
        int y=e[i].to;
        if(d[x]+1==d[y]&&e[i].w)
        {
            f=dfs(y,min(flow-rest,e[i].w));
            e[i].w-=f;rest+=f;e[i^1].w+=f;
            if(flow==rest) return rest;
        }
    }
    if(!rest) d[x]=-1;
    return rest;
}
int dinic()
{
    int r=0;
    while(bfs()) r+=dfs(s,1e9);
    return r;
}
int main()
{
    memset(l,-1,sizeof(l));
    k=read();n=read();s=k+n+1;t=s+1;
    for(int i=1;i<=k;i++) sum+=(num[i]=read()),add(i+n,t,num[i]);
    for(int i=1,o;i<=n;i++)
    {
        o=read();
        for(int j=1,p;j<=o;j++)
        {
            p=read();
            add(i,n+p,1);
        }
        add(s,i,1);
    }
    if(dinic()<sum) return printf("No Solution!")&0;
    for(int i=1;i<=k;putchar(10),i++)
    {
        write(i);putchar(':');
        for(int j=l[i+n];~j;j=e[j].next)
        if(e[j].to!=t&&e[j].w==1)
         write(e[j].to),putchar(32);
    }
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/80790655