基本概念
#include
using namespace std;
const int N = 1010, M = 20010, INF = 1e8;
int n, m, S, T;
int h[N], f[M], e[M], ne[M], idx;
//d 到当前节点的最小流量,pre 存从哪个边转移过来.
int q[N], d[N], pre[N];
bool st[N];
void add(int a, int b, int c)
{
e[idx] = b, ne[idx] = h[a], f[idx] = c, h[a] = idx++;
e[idx] = a, ne[idx] = h[b], f[idx] = 0, h[b] = idx++;
}
bool bfs()
{
int hh = 0, tt = 0;
memset(st, false, sizeof st);
q[0] = S, st[S] = true, d[S] = INF;
while(hh <= tt){
int u = q[hh++];
for(int i = h[u]; i != -1; i = ne[i]){
int v = e[i];
if(st[v] || f[i] == 0) continue;
st[v] = true;
d[v] = min(d[u], f[i]);
pre[v] = i;
if(v == T) return true;
q[++tt] = v;
}
}
return false;
}
int EK()
{
int res = 0;
while(bfs()){
res += d[T];
for(int i = T; i != S; i = e[pre[i] ^ 1]){
f[pre[i]] -= d[T], f[pre[i] ^ 1] += d[T];
}
}
return res;
}
int main()
{
scanf("%d%d%d%d", &n, &m, &S, &T);
memset(h, -1, sizeof h);
while(m--){
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
printf("%d\n", EK());
return 0;
}
#include
using namespace std;
const int N = 10100, M = 200010, INF = 1e8;
int n, m, S, T;
int h[N], f[M], e[M], ne[M], idx;
//d 到当前节点的最小流量,pre 存从哪个边转移过来.
int q[N], d[N], cur[N];
void add(int a, int b, int c)
{
e[idx] = b, ne[idx] = h[a], f[idx] = c, h[a] = idx++;
e[idx] = a, ne[idx] = h[b], f[idx] = 0, h[b] = idx++;
}
bool bfs()
{
//按照所有点到原点的距离建立分层图,并且更新当前弧(即优先榨取的边)
memset(d, -1, sizeof d);
int hh = 0, tt = 0;
q[0] = 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])
{
d[v] = d[u] + 1;
cur[v] = h[v];
if(v == T) return true;
q[++tt] = v;
}
}
}
return false;
}
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])
{
cur[u] = i; //当前弧优化
int v = e[i];
if(d[v] == d[u] + 1 && f[i])
{
int t = find(v, min(f[i], limit - flow));
if(!t) d[v] = -1;
f[i] -= t, f[i ^ 1] += t, flow += t;
}
}
return flow;
}
int dinic()
{
int res = 0, flow;
while(bfs()) while(flow = find(S, INF)) res += flow;
return res;
}
int main()
{
scanf("%d%d%d%d", &n, &m, &S, &T);
memset(h, -1, sizeof h);
while(m--)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
printf("%d\n", dinic());
return 0;
}
#include
using namespace std;
const int N = 110, M = 5210, INF = 1e8;
int h[N], e[M], ne[M], f[M], idx;
int q[N], cur[N], d[N];
int n, m, S, T;
//略去 dinic 的模板,只保留建图模板.
int main()
{
memset(h, -1, sizeof h);
scanf("%d%d", &m, &n);
S = n + 1, T = n + 2;
int a, b;
while(cin >> a >> b, a != -1)
{
add(a, b, 1);
}
for(int i = 1; i <= m; i++) add(S, i, 1);
for(int i = m + 1; i <= n; i++) add(i, T, 1);
printf("%d\n", dinic());
for(int i = 0; e[i ^ 1] != S; i += 2)
{
if(f[i] == 0) printf("%d %d\n", e[i ^ 1], e[i]);
}
}
题意:假设有来自 m m m 个不同单位的代表参加一次国际会议。每个单位的代表数分别为 r i ( i = 1 , 2 , … , m ) r_i(i=1,2,\dots,m) ri(i=1,2,…,m)。会议餐厅共有 n n n 张餐桌,每张餐桌可容纳 c i ( i = 1 , 2 , … , n ) c_i(i=1,2,\dots,n) ci(i=1,2,…,n) 个代表就餐。为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐。试设计一个算法,给出满足要求的代表就餐方案。
二分图的多重匹配问题,构造一个二分图,源点连向左半部分的图,边的容量是点权;右半部分的图向汇点连边,容量也是点权;左右两部分的结点两两相连,容量为1.
// 省去 dinic 模板部分,只保留建图
int main()
{
memset(h, -1, sizeof h);
scanf("%d%d", &m, &n);
S = 0, T = n + m + 1;
int tot = 0;
for(int i = 1; i <= m; i++)
{
int r;
scanf("%d", &r);
tot += r;
add(S, i, r);
}
for(int i = m + 1; i <= m + n; i++)
{
int c;
scanf("%d", &c);
add(i, T, c);
}
for(int i = 1; i <= m; i++)
{
for(int j = 1; j <= n; j++)
{
add(i, j + m, 1);
}
}
int res = dinic();
if(res != tot) printf("0\n");
else
{
printf("1\n");
for(int u = 1; u <= m; u++)
{
for(int i = h[u]; i != -1; i = ne[i])
{
if(m + 1 <= e[i] && e[i] <= m + n && !f[i])
{
printf("%d ", e[i] - m);
}
}
printf("\n");
}
}
return 0;
}
int main()
{
memset(h, -1, sizeof h);
scanf("%d%d", &n, &m);
S = 0, T = n + 1;
for(int i = 1; i <= m; i++)
{
int a, b, c, d;
scanf("%d%d%d%d", &a, &b, &c, &d);
add(a, b, c, d);
A[a] -= c, A[b] += c;
}
int tot = 0;
for(int i = 1; i <= n; i++)
{
if(A[i] > 0) add(S, i, 0, A[i]), tot += A[i];
else if(A[i] < 0) add(i, T, 0, -A[i]);
}
if(dinic() != tot) printf("NO\n");
else
{
printf("YES\n");
for(int i = 0; i < 2 * m; i += 2)
{
//注意流量要输出反向边
printf("%d\n", f[i ^ 1] + l[i]);
}
}
return 0;
}