Luo Gu P3254-- roundtable maximum flow problem [+ & Dinic algorithm optimization & Alternative greedy solution]

Topic Portal


Title Description

Suppose there representatives from m different units participated in an international conference. It represents the number per unit respectively ri (i = 1,2, ......, m).

Restaurant meeting there are n of tables, each table can accommodate ci (i = 1,2, ......, n) representative meal.

To enable delegates to the full exchange, hoping not to eat from the same unit to represent the same table. Try to design an algorithm, given on behalf of feeding programs to meet the requirements.

For a given number and represents the number of tables and table capacity, calculates a representative programming feeding programs to meet the requirements.


Input Format

Line 1 has two positive integers m and n, m represents the number of units, n represents a number of tables, 1 <= m <= 150, 1 <= n <= 270.

Row 2 with m a positive integer, respectively, represents the number of each unit.

Line 3 has n positive integers, respectively, each of the table capacity.


Output Format

If the problem is solvable, the first line of output 1, output 0 otherwise. The next m rows are given to each unit represents a table number. If there are a plurality of programs to meet the requirements, so long as the output of a program.


Entry

4 5
4 5 3 5
3 5 2 6 4

Export

1
1 2 4 5
1 2 3 4 5
2 4 5
1 2 3 4 5


answer

  • Compare refreshing maximum flow ( odd water incomparable )

  • This question Jian feeling is still very apparent Figure

  • First, it can be seen a significant bipartite graph model , the unit is a point , the table is another point , the number can be seen as representative of the flow rate.

  • From s s is connected to all single site, the number of the representative capacity. single site between the table and the one-tap two linkage capacity 1 1 limit side represented "the same units representing not eat at the same table". Point the table again t t even a capacity for the number of sides of the table to limit the size of the dining table.

    In this case, each unit represents a traffic representative. They flow through the points and edges on behalf of their characteristics. The capacity is limiting the representatives of ...

  • As for the output of the program, as long as we see from one site to the table edges which point a full load, while a fully loaded ( u , v ) (U, v) the meaning is in the best scenario from a u in represents the unit's representatives sat down v v on the table represents.

    Of course, if the maximum flow does not run over (the maximum flow is not equal to the number of representatives) , then certainly have not been allocated on behalf of, the determination is no solution.


Toxic greedy solution

blind ** Greedy strategy:

  • The first row of a table, in descending order, from largest to smallest scale repeat units of a row sequence. So what use is it? The larger the size of the unit because the harder to meet, so we prioritize them;

  • For a table you can think, the more your desk is clearly easier to meet the meaning of problems, and because it is easy to take a small table caused the explosion can not be used, so we prefer to grow in the table.


AC-Code

  • Dinic solution:
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int inf = 0x3f3f3f3f;
const int maxn = 150 * 270 + 150 + 270;
int n, m;

struct Edge {
	int to;
	int next;
	int val;
}edge[maxn << 1]; // 双向边,开 2 倍数组
int head[maxn];
int cnt; // 边的数量,从 0 开始编号
int depth[maxn]; // 分层图标记深度
int cur[maxn]; // 当前弧优化,记录当前点 u 循环到了哪一条边
void add(int u, int v, int w) {
	edge[cnt].to = v;
	edge[cnt].next = head[u];
	edge[cnt].val = w;
	head[u] = cnt++;
}

// bfs分层图
bool bfs(int s, int t) {
	queue<int>q;
	memset(depth, 0, sizeof depth);
	depth[s] = 1; // 源点深度为 1
	cur[s] = head[s];
	q.push(s);
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		for (int i = head[u]; ~i; i = edge[i].next) {
			int v = edge[i].to;
			if (edge[i].val > 0 && depth[v] == 0) { // 如果残量不为0,且 v 还未分配深度
				depth[v] = depth[u] + 1;
				cur[v] = head[v]; //------当前弧优化,注意在bfs里,这样做到了“按需赋值”,因为Dinic本来上界就松得一匹, BFS的过程中不连通的点根本就不用再管了...
				if (v == t) // -----分层图汇点优化:遇到汇点直接返回------
					return true;
				q.push(v);
			}
		}
	}
	return depth[t]; // 汇点深度为 0:不存在分层图,返回false;
					 //           非 0 :存在增广路,返回true
}

// dfs寻找增广路
int dfs(int u, int flow, int t) {
	if (u == t || flow <= 0) // 到达汇点
		return flow;
	int rest = flow;
	for (int i = cur[u]; ~i; i = edge[i].next) {
		int v = edge[i].to;
		if (depth[v] == depth[u] + 1 && edge[i].val != 0) { // 满足分层图、残量>0 两个条件
			int k = dfs(v, min(rest, edge[i].val), t); // 向下增广
			if (k < 0) // ------无用点优化-----
				depth[v] = 0;
			rest -= k;
			edge[i].val -= k; // 正向边减
			edge[i ^ 1].val += k; // 反向边加
			if (rest <= 0) //------剩余量优化:在进行增广的时候,如果该节点已经没有流量,直接退出------
				break;
		}
	}
	return flow - rest; // flow:推送量,rest:淤积量,flow - rest:接受量/成功传递量
}
int Dinic(int s, int t) {
	int ans = 0;
	while (bfs(s, t)) {
		ans += dfs(s, inf, t);
	}
	return ans;
}
int main() {
	ios;
	while (cin >> m >> n) {
		cnt = 0;
		memset(head, -1, sizeof head);
		int peoplenum = 0;
		for (int i = 1, k; i <= m; ++i) {
			cin >> k;
			peoplenum += k;
			add(0, i, k);
			add(i, 0, 0);
		}
		for (int i = 1, k; i <= n; ++i) {
			cin >> k;
			for (int j = 1; j <= m; ++j) {
				add(j, m + i, 1);
				add(m + i, j, 0);
			}
			add(m + i, m + n + 1, k);
			add(m + n + 1, m + i, 0);
		}
		if (Dinic(0, m + n + 1) == peoplenum) {
			cout << 1 << endl;
			for (int i = 1; i <= m; ++i) {
				for (int j = head[i]; ~j; j = edge[j].next) {
					int v = edge[j].to;
					if (v != 0 && !edge[j].val)
						cout << v - m << " ";
				}
				cout << endl;
			}
		}
		else
			cout << 0 << endl;
	}
}

  • Greedy solution
#include <bits/stdc++.h>
using namespace std;
const int maxn = 305, maxm = 205;
int d[maxn], z[maxn], wow[maxn];
int m ,n;
struct lpl
{
    int num, data;
}desk[maxn], people[maxm];
bool operator < (lpl a, lpl b)
{
    return a.data > b.data;
}
vector<int> ld[maxm];
inline void putit()
{
    scanf("%d%d", &m, &n);
    for(int i = 1; i <= m; ++i)
    {
        scanf("%d", &d[i]);
        people[i].num = i; people[i].data = d[i];
    }    
    for(int i = 1; i <= n; ++i)
    {
        scanf("%d", &z[i]);
        desk[i].num = i; desk[i].data = z[i];
    }
}
inline void print()
{
    printf("1\n");
    for(int i = 1; i <= m; ++i)
    {
        for(int j = 0; j < ld[i].size(); ++j)
        {
            printf("%d ", ld[i][j]);
        }
        printf("\n");
    }
}
int main()
{
    putit(); 
    sort(desk + 1, desk + n + 1); 
    sort(people + 1, people + m + 1);
    for(int i = 1; i <= m; ++i)
    {
        int qwe = 1;
        for(int j = 0; j < people[i].data; ++j)
        {
            bool flag = false;
            for(int t = qwe; t <= n; ++t)
            {
                if(wow[ desk[t].num ] < desk[t].data)
                {
                    wow[ desk[t].num ]++; qwe = t + 1;
                    flag = true; ld[ people[i].num ].push_back(desk[t].num); 
                    break;
                }
            }
            if(flag == false) 
            {
                 printf("0");
                 return 0;
            }
        }
    }
    print();
    return 0;
}
发布了104 篇原创文章 · 获赞 60 · 访问量 5847

Guess you like

Origin blog.csdn.net/Q_1849805767/article/details/103605294