本文旨在对于个人知识的梳理以及知识的分享,如果有不足的地方,欢迎大家在评论区指出
在讲述今天的题目之前,需要先总结一下使用最大流解决问题的一个基本的思路:
首先我们假设问题的可行解为A,而我们通过建图求得的所有可行流集合为B,我们只需要证明A中的每一个方案与B中的每一条可行流一一对应,那么A中方案的最优解就与B中的可行流的最优解对应,其实也就是B中的最大流对于A中的最优方案
第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员。
由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的 2 2 2 名飞行员,其中 1 1 1 名是英国飞行员,另 1 1 1 名是外籍飞行员。
在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合。
如何选择配对飞行的飞行员才能使一次派出最多的飞机。
对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。
第 1 1 1 行有 2 2 2 个正整数 m m m 和 n n n。 m m m 是外籍飞行员数; n n n 是皇家空军的飞行员总数。
外籍飞行员编号为 1 ∼ m 1∼m 1∼m;英国飞行员编号为 m + 1 ∼ n m+1∼n m+1∼n。
接下来每行有 2 2 2 个正整数 i i i 和 j j j,表示外籍飞行员 i i i 可以和英国飞行员 j j j 配合。
文件最后以 2 2 2 个 − 1 −1 −1 结束。
第 1 1 1 行是最佳飞行员配对方案一次能派出的最多的飞机数 M M M。
接下来 M M M 行是最佳飞行员配对方案。
每行有 2 2 2 个正整数 i i i 和 j j j,表示在最佳飞行员配对方案中,外籍飞行员 i i i 和英国飞行员 j j j 配对。
如果有多种配对方案,则输出任意一种即可,方案内部配对输出顺序随意。
1 < m < n < 100 1
5 10
1 7
1 8
2 6
2 9
2 10
3 7
3 8
4 7
4 8
5 10
-1 -1
4
1 7
2 9
3 8
5 10
import java.io.*;
import java.util.*;
class Main{
static int N = 110, M = 5210, INF = 0x3f3f3f3f;
static int[] h = new int[N];
static int[] e = new int[M];
static int[] f = new int[M];
static int[] ne = new int[M];
static int[] q = new int[N];
static int[] cur = new int[M];
static int[] d = new int[N];
static int idx, s, t;
static void add(int a, int b, int c){
e[idx] = b;
f[idx] = c;
ne[idx] = h[a];
h[a] = idx ++;
}
static boolean bfs(){
int hh = 0; int tt = -1;
Arrays.fill(d, -1);
q[++ tt] = s; d[s] = 0; cur[s] = h[s];
while(hh <= tt){
int u = q[hh ++];
for(int i=h[u]; i!=-1; i=ne[i]){
int v = e[i];
if(d[v]==-1 && f[i] != 0){
d[v] = d[u] + 1;
cur[v] = h[v];
if(v == t) return true;
q[++ tt] = v;
}
}
}
return false;
}
static int find(int u, int limit){
if(u == t) return limit;
int flow = 0;
for(int i=cur[u]; i!=-1 && flow<limit; i=ne[i]){
int v = e[i];
cur[u] = i;
if(d[v]==d[u]+1 && f[i] != 0){
int t = find(v, Math.min(f[i], limit-flow));
if(t == 0) d[v] = -1;
f[i] -= t; f[i^1] += t; flow += t;
}
}
return flow;
}
static int dinic(){
int res = 0; int flow = 0;
while(bfs()){
while((flow=find(s, INF)) != 0){
res += flow;
}
}
return res;
}
public static void main(String[] args) throws IOException{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
Arrays.fill(h, -1);
String[] cur = in.readLine().split(" ");
int m = Integer.parseInt(cur[0]);
int n = Integer.parseInt(cur[1]);
// 加边
s = 0; t = n + 1;
for(int i=1; i<=m; i++){
add(s, i, 1);
add(i, s, 0);
}
for(int i=m+1; i<=n; i++){
add(i, t, 1);
add(t, i, 0);
}
while(true){
String[] arr = in.readLine().split(" ");
int a = Integer.parseInt(arr[0]);
int b = Integer.parseInt(arr[1]);
if(a == -1) break;
add(a, b, 1);
add(b, a, 0);
}
System.out.println(dinic());
for(int i=0; i<idx; i+=2){
if(e[i]>m && e[i]<=n && f[i]==0){
System.out.println(e[i^1] + " " + e[i]);
}
}
}
}
假设有来自 m m m 个不同单位的代表参加一次国际会议。
每个单位的代表数分别为 r i ( i = 1 , 2 , … , m ) r_{i}(i=1,2,…,m) ri(i=1,2,…,m)。
会议餐厅共有 n n n 张餐桌,每张餐桌可容纳 c i ( i = 1 , 2 , … , n ) c_{i}(i=1,2,…,n) ci(i=1,2,…,n) 个代表就餐。
为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐。
试设计一个算法,给出满足要求的代表就餐方案。
第 1 1 1 行有 2 2 2 个正整数 m m m 和 n n n, m m m 表示单位数, n n n 表示餐桌数。
第 2 2 2 行有 m m m 个正整数,分别表示每个单位的代表数 r i r_{i} ri。
第 3 3 3 行有 n n n 个正整数,分别表示每个餐桌的容量 c i c_{i} ci。
如果问题有解,在第 1 1 1 行输出 1 1 1,否则输出 0 0 0。
接下来的 m m m 行给出每个单位代表的就餐桌号。
如果有多个满足要求的方案,只要求输出 1 1 1 个方案。
1 ≤ m ≤ 150 1≤m≤150 1≤m≤150,
1 ≤ n ≤ 270 1≤n≤270 1≤n≤270,
1 ≤ r i , c i ≤ 100 1≤r_{i},c_{i}≤100 1≤ri,ci≤100
4 5
4 5 3 5
3 5 2 6 4
输出样例:
1
1 2 4 5
1 2 3 4 5
2 4 5
1 2 3 4 5
import java.io.*;
import java.util.*;
class Main{
static int N = 535, M = (150*270+N)*2, INF = 0x3f3f3f3f;
static int[] h = new int[N];
static int[] e = new int[M];
static int[] ne = new int[M];
static int[] f = new int[M];
static int[] d = new int[N];
static int[] q = new int[N];
static int[] cur = new int[M];
static int idx, s, t;
static void add(int a, int b, int c){
e[idx] = b;
f[idx] = c;
ne[idx] = h[a];
h[a] = idx ++;
}
static boolean bfs(){
int hh = 0; int tt = -1;
Arrays.fill(d, -1);
q[++ tt] = s; d[s] = 0; cur[s] = h[s];
while(hh <= tt){
int u = q[hh ++];
for(int i=h[u]; i!=-1; i=ne[i]){
int v = e[i];
if(d[v]==-1 && f[i]!=0){
d[v] = d[u]+1;
cur[v] = h[v];
if(v == t) return true;
q[++ tt] = v;
}
}
}
return false;
}
static int find(int u, int limit){
if(u == t) return limit;
int flow = 0;
for(int i=cur[u]; i!=-1 && flow < limit; i=ne[i]){
int v = e[i];
cur[u] = i;
if(d[v]==d[u]+1 && f[i] != 0){
int t = find(v, Math.min(f[i], limit-flow));
if(t == 0) d[v] = -1;
f[i] -= t; f[i^1] += t; flow += t;
}
}
return flow;
}
static int dinic(){
int res = 0; int flow = 0;
while(bfs()){
while((flow=find(s, INF)) != 0){
res += flow;
}
}
return res;
}
public static void main(String[] args) throws IOException{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
Arrays.fill(h, -1);
String[] cur = in.readLine().split(" ");
int m = Integer.parseInt(cur[0]);
int n = Integer.parseInt(cur[1]);
// 加边
s = 0; t = m + n + 1;
int tot = 0; // 用于计算总人数
String[] arr = in.readLine().split(" ");
for(int i=1; i<=m; i++){
int c = Integer.parseInt(arr[i-1]);
tot += c;
add(s, i, c);
add(i, s, 0);
}
String[] tmp = in.readLine().split(" ");
for(int i=1; i<=n; i++){
int c = Integer.parseInt(tmp[i-1]);
add(i+m, t, c);
add(t, i+m, 0);
}
for(int i=1; i<=m; i++){
for(int j=1; j<=n; j++){
add(i, j+m, 1);
add(j+m, i, 0);
}
}
if(dinic() != tot){
System.out.println(0);
}else{
System.out.println(1);
for(int i=1; i<=m; i++){
for(int j=h[i]; j!=-1; j=ne[j]){
if(f[j] == 0){
System.out.print((e[j]-m) + " ");
}
}
System.out.println();
}
}
}
}