【网络流24题】圆桌问题

链接

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

大意

n <= 150 个单位,每个单位有 a i 个人,现在有 m 个桌子,每个桌子可以容纳 b i 个人,请问在是否存在一种方案使得所有人都有桌子坐并且同桌子的人不同单位?

思路

最大流求最大匹配
先拆点,每个节点拆成 i . a i . b ,分别表示单位和桌子

把单位和源点相连,容量为该单位拥有的人数
把桌子和汇点相连,容量为桌子可容纳的人数
把每个单位和桌子相连,容量为1(每个单位在每个桌子只能有一个人)
再求最大流

其中在求最大流的过程中,加上一个 t o 表示第 i 个单位是否坐在第 j 张桌子
如果该边的起点是单位终点是桌子,那么 t o [ x ] [ y n ] 赋值为 t r u e
弱国该边的起点是桌子终点是单位(反向边),那么 t o [ y ] [ x n ] = 0

代码

#include<cstring>
#include<cstdio>
#include<queue>
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
using namespace std;int n,m,f,sum;
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[100001];int d[50001],l[50001],tot,s,t,a;
bool to[151][271];
void add(int u,int v,int w)
{
    e[tot]={l[u],v,w};l[u]=tot++;
    e[tot]={l[v],u,0};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;i=e[i].next)
    {
        int y=e[i].to;
        if(e[i].w&&d[y]==d[x]+1)
        {
            f=dfs(y,min(flow-rest,e[i].w));
            if(!f) continue;
            if(x<=n&&n<y) to[x][y-n]=1;
            if(y<=n&&n<x) to[y][x-n]=0;
            e[i].w-=f;e[i^1].w+=f;rest+=f;
            if(rest==flow) break;
        }
    }
    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));
    n=read();m=read();s=n+m+1;t=s+1;
    for(int i=1;i<=n;i++) sum+=(a=read()),add(s,i,a);
    for(int i=1;i<=m;i++) a=read(),add(i+n,t,a);
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) add(i,j+n,1);
    if (dinic()==sum) putchar(49);else return putchar(48)&0;
    putchar(10);
    for(int i=1;i<=n;putchar(10),i++)
     for(int j=1;j<=m;j++)
      if(to[i][j]) write(j),putchar(32);
}

代码2

在输出的基础上加上一个 v e c t o r 库,空间换时间

#include<cstring>
#include<vector>
#include<cstdio>
#include<queue>
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
using namespace std;int n,m,f,sum;
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[100001];int d[50001],l[50001],tot,s,t,a;
bool to[151][271];
vector<int>ans[151];
void add(int u,int v,int w)
{
    e[tot]={l[u],v,w};l[u]=tot++;
    e[tot]={l[v],u,0};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;i=e[i].next)
    {
        int y=e[i].to;
        if(e[i].w&&d[y]==d[x]+1)
        {
            f=dfs(y,min(flow-rest,e[i].w));
            if(!f) continue;
            if(x<=n&&n<y) to[x][y-n]=1,ans[x].push_back(y-n);
            if(y<=n&&n<x) to[y][x-n]=0;
            e[i].w-=f;e[i^1].w+=f;rest+=f;
            if(rest==flow) break;
        }
    }
    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));
    n=read();m=read();s=n+m+1;t=s+1;
    for(int i=1;i<=n;i++) sum+=(a=read()),add(s,i,a);
    for(int i=1;i<=m;i++) a=read(),add(i+n,t,a);
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) add(i,j+n,1);
    if (dinic()==sum) putchar(49);else return putchar(48)&0;
    putchar(10);
    for(int i=1;i<=n;putchar(10),i++)
     for(int j=0;j<ans[i].size();j++)//加快速度
      if(to[i][ans[i][j]]) write(ans[i][j]),putchar(32);
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/80769314
今日推荐