【网络流24题】解题报告:E 、圆桌问题(最大流求二分图多重匹配)

E 、圆桌问题(最大流求二分图多重匹配)【省选/NOI-

在这里插入图片描述
可以直观的想到,二分图的左边是单位,右边是桌子
由于题目的限制 每个单位只能在一个桌子坐一个人
所以我们就把每个单位向各个桌子连一道流量为1的边,这样每次流一次一个单位只能贡献1个流量,也就是一个人到一个桌子上,满足题意。

然后由超级源点与每个单位连接,边的权值为单位人数
由每个圆桌与超级汇点连接,边的权值为圆桌人数

然后跑一下最大匹配 如果最大匹配数等于所有单位的人数和
那么就可以 完全安排 否则不能完全安排
然后再枚举一下,如果剩余流量 == 0则该点为方案之一,输出即可。
在这里插入图片描述

然后我因为用了成对变换而tot没有赋初值1而WA了一个小时没有找到bug。。。以后tot只写1.

#include
using namespace std;

typedef long long ll;
typedef pair<int,int> PII;

const int N = 3000001, M = 30000010, INF = 0x3f3f3f3f;
int ver[M], nex[M], edge[M], head[N], tot = 1;
int n, m, s, t;
bool vis[N];
int maxflow;
int deep[N];//层级数,其实应该是level
int now[M];//当前弧优化

void add(int x, int y, int z){
     
    ver[++tot] = y;
    edge[tot] = z;
    nex[tot] = head[x];
    head[x] = tot;

    ver[++tot] = x;
    edge[tot] = 0;
    nex[tot] = head[y];
    head[y] = tot;
}

bool bfs(){
     //在残量网络中构造分层图
    memset(deep,0x3f,sizeof deep);
    queue<int>q;
    q.push(s);
    deep[s] = 0;
    now[s] = head[s];//一些初始化
    while(!q.empty()){
     
        int x = q.front();
        q.pop();
        for(int i = head[x];i;i = nex[i]){
     
            int y = ver[i];
            if(edge[i] > 0 && deep[y] == INF){
     //没走过且剩余容量大于0
                q.push(y);
                now[y] = head[y];//先初始化,暂时都一样
                deep[y] = deep[x] + 1;
                if(y == t)return 1;//找到了
            }
        }
    }
    return 0;
}

//flow是整条增广路对最大流的贡献,rest是当前最小剩余容量,用rest去更新flow
int dfs(int x,int flow){
     //在当前分层图上增广
    if(x == t)return flow;
    int ans = 0,k,i;
    for(i = now[x];i && flow;i = nex[i]){
     
        now[x] = i;//当前弧优化(避免重复遍历从x出发的不可拓展的边)
        int y = ver[i];
        if(edge[i] > 0 && (deep[y] == deep[x] + 1)){
     //必须是下一层并且剩余容量大于0
            k = dfs(y,min(flow,edge[i]));//取最小
            if(!k)deep[y] = INF;//剪枝,去掉增广完毕的点
            edge[i] -= k;//回溯时更新
            edge[i ^ 1] += k;//成对变换
            ans += k;
            flow -= k;
        }
        //if(!flow)return rest;
    }
    return ans;
}

void Dinic(){
     
    while(bfs())
        maxflow += dfs(s,INF);
}

int people;

int main(){
     
    scanf("%d%d", &m, &n);
    s = 0,t = 10000;
    for(int i = 1; i <= m; ++ i){
     
        int x;
        scanf("%d",&x);
        add(s, i, x);
        people += x;
    }
    for(int i = 1;i <= n;++i){
     
        int x;
        scanf("%d",&x);
        add(i + m,t,x);
    }
    for(int i = 1; i <= m; i ++ )
        for(int j = 1; j <= n; ++j)
            add(i, j + m, 1);
    Dinic();
    if(people == maxflow){
     
        puts("1");
        for(int i = 1;i <= m;++i){
     
            for(int j = head[i];j;j = nex[j]){
     
                int y = ver[j], z = edge[j];
                if(y != s && !z)
                    printf("%d ",y - m);
            }
            puts("");
        }
    }
    else puts("0");
    return 0;
}

你可能感兴趣的:(#,线性规划与网络流24题,#,最大流)