• P3254 圆桌问题


    题目描述

    Link

    有来自 (m) 个不同单位的代表参加一次国际会议。第 (i) 个单位派出了 (r_i) 个代表。

    会议的餐厅共有 (n) 张餐桌,第 (i) 张餐桌可容纳 (c_i) 个代表就餐。

    为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐。请给出一个满足要求的方案.


    第二道网络流24题 (应该算是比较简单的吧,毕竟自己这种蒟蒻都能想出来),芜湖起飞。

    比较好想的二分图多重匹配问题。

    我们从源点向每个单位连一条容量为 (r_i) 的边,表示这个单位需要在 (r_i) 张不同的桌子就餐。

    在从餐桌向汇点连一条容量为 (c_i) 的边,表示这个餐桌最多能容纳 (c_i) 个人,也就是用来限制最大流的流量。

    剩下的就把每个单位和每个餐桌之间连一条容量为 (1) 边,表示这个单位最多可以派一个人到那个餐桌就餐。

    我们跑出来的最大流就是满足这样就餐的最多的人数。

    无解的情况特判一下就可以。

    输出方案的话就在残留网络中找边权为 (0) 的边输出就行。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    using namespace std;
    const int inf = 2147483647;
    const int N = 1010;
    int n,m,s,t,ans,sum,x,tot = 1;
    int head[N],dep[N];
    struct node
    {
    	int to,net,w;
    }e[100010];
    inline int read()
    {
    	int s = 0, w = 1; char ch = getchar();
    	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
    	return s * w;
    }
    void add(int x,int y,int w)
    {
    	e[++tot].w = w;
    	e[tot].to = y;
    	e[tot].net = head[x];
    	head[x] = tot;
    }
    bool bfs()
    {
    	memset(dep,0,sizeof(dep));
    	queue<int> q;
    	q.push(s); dep[s] = 1;
    	while(!q.empty())
    	{
    		int x = q.front(); q.pop();
    		for(int i = head[x]; i; i = e[i].net)
    		{
    			int to = e[i].to;
    			if(e[i].w && !dep[to])
    			{
    				q.push(to);
    				dep[to] = dep[x] + 1;
    				if(to == t) return 1;
    			}
    		}
    	}
    	return 0;
    }
    int dinic(int x,int flow)
    {
    	if(x == t) return flow;
    	int rest = flow;
    	for(int i = head[x]; i; i = e[i].net)
    	{
    		int to = e[i].to;
    		if(e[i].w && dep[to] == dep[x] + 1)
    		{
    			int k = dinic(to,min(e[i].w,rest));
    			if(!k) dep[to] = 0;
    			e[i].w -= k;
    			e[i^1].w += k;
    			rest -= k;
    		}
    	}
    	return flow - rest;
    }
    int main()
    {
    	n = read(); m = read();
    	s = 0; t = n+m+1;
    	for(int i = 1; i <= n; i++)
    	{
    		x = read(); sum += x;
    		add(s,i,x); add(i,s,0);//源点向每个单位连一条边
    	}
    	for(int i = 1; i <= m; i++)
    	{
    		x = read();
    		add(n+i,t,x); add(t,n+i,0);//每个桌子向汇点连边
    	}
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= m; j++)
    		{
    			add(i,n+j,1); add(n+j,i,0);//单位和餐桌之间互相连边
    		}
    	}
    	int flow = 0;
    	while(bfs())
    	{
    		while(flow = dinic(s,inf)) ans += flow;
    	}
    	if(ans < sum)
    	{
    		printf("%d
    ",0);
    		return 0;
    	}
    	printf("%d
    ",1);
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = head[i]; j; j = e[j].net)
    		{
    			int to = e[j].to;
    			if(e[j].w == 0) printf("%d ",to-n);
    		}
    		printf("
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    校内模拟赛吧 ———— 2019.10.30
    牛客CSP-S提高组赛前集训营1———2019.10.29 18:30 至 22:00
    关于gcd
    洛谷 P1156 垃圾陷阱 题解
    选球游戏 题解———2019.10.19
    小梵同学前进!
    小梵同学 GO!
    先天八卦向后天八卦演进逻辑猜想
    [delphi]在DLL中多线程同步Synchronize卡死问题
    GDI与GDI+性能比较
  • 原文地址:https://www.cnblogs.com/genshy/p/13733606.html
Copyright © 2020-2023  润新知