下面是模板代码:
/*
特别注意:::以下建边tot从2开始记录!
1.建图
对于每一个(a, b, low, up)
首先建立(a, b, up - low)
并记录: div[a]-=low, div[b]+=low
待全部边都建好之后, 对于每个点:
if (div[i] < 0) add(i, TT, -du[i]);
if (div[i] > 0) add(SS, i, du[i]), flow += du[i];
2.可行流
如果有源汇点,加边(t, s, inf)
if (Dinic(SS, TT) != flow) 无解
否则有解
3.最大流
在执行完1,2中所有操作后,如果有解:
MaxFlow = Dinic(s, t)
其中按照建边顺序的第i个边的流量为
eflow[i] = low[i]+e[( (i+1) <<1)-1] (因为边从2开始记录)
4.最小流
在执行完1中所有操作后
MaxFlow1 = Dinic(SS, TT)
加边(t, s, inf)
MaxFlow2 = Dinic(SS, TT)
if (MaxFLow1 + MaxFLow2 != flow) 无解
ans = eflow<t, s>
其中按照建边顺序的第i个边的流量同3
*/
//模板题来自::ZOJ 3229
int ans[N]; int day[N];
int SS, TT, flow;
int du[N];
void add(int x, int y, int w = 1)
{
ver[++tot] = y;
ne[tot] = he[x];
e[tot] = w;
he[x] = tot;
ver[++tot] = x;
ne[tot] = he[y];
e[tot] = 0;
he[y] = tot;
}
void madd(int x, int y, int low, int up)
{
add(x, y, up - low);
du[x] -= low;
du[y] += low;
}
void DoneAdd(int r)
{
for (int i = 0; i <= r; i++)
{
if (du[i] < 0) add(i, TT, -du[i]);
else if (du[i] > 0) add(SS, i, du[i]), flow += du[i];
}
}
void init()
{
tot = 1;
SS = N - 2, TT = N- 3;
flow = 0;
memset(he, 0, sizeof(he));
memset(du, 0, sizeof(du));
memset(ans, 0, sizeof(ans));
}
int main()
{
int n, m;
while(scanf("%d%d", &n, &m) != EOF)
{
init();
int cnt = 1;
int s = n + m + 1, t = s + 1;
for (int i = 1; i <= m; i++)
{
int te; scanf("%d", &te);
du[n+i] -= te;
du[t] += te;
}
for (int i = 1; i <= n; i++)
{
int c, d;
scanf("%d%d", &c, &d);
day[i] = d;
for (int j = 1; j <= c; j++)
{
int a, l, r;
scanf("%d%d%d", &a, &l, &r);
ans[++cnt] = l;
madd(i, a+n+1, l, r);
}
}
for (int i = 1; i <= n; i++) add(s, i, day[i]);
for (int i = 1; i <= m; i++) add(i+n, t, inf);
DoneAdd(t);
add(t, s, inf);
int rest = Dinic(SS, TT);
if (rest != flow) puts("-1");
else
{
int anss = Dinic(s, t);
printf("%d\n", anss);
for (int i = 2; i <= cnt; i++)
printf("%d\n", e[i*2-1] + ans[i]);
}
puts("");
}
return 0;
}