最大流建图是关键,将一个题目转化为最大流,要有清晰的建图思想。
这道题注意构建源点和汇点,然后直接套模板。
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn = 220;
const int inf = 10000000;//不要开太大
int c[maxn][maxn];
int q[maxn], pre[maxn];
int level[maxn], gap[maxn];
int n, m, np, nc;
int s, t;
void init_sap(){
memset(level, 10, sizeof (level));
//printf("--- %d\n", level[2]);
//for(int i = 0; i <= n; i ++) level[i] = n + 310;
memset(gap, 0, sizeof gap);
memset(pre, -1, sizeof pre);
int qs = 0, qe = 0;
q[qe++] = t;
level[t] = 0;
gap[ level[t] ] ++;
while(qs < qe){
int hd = q[qs++];
for(int i = 1; i <= n; i ++){
if(level[i] > n && c[i][hd] > 0){//level[i] >= n 也可以,why ?
q[qe++] = i;
level[i] = level[hd] + 1;
gap[ level[i] ] ++;
}
}
}
}
int find_path(int u){
for(int i = 1; i <= n; i ++)
if(c[u][i] > 0 && level[u] == level[i] + 1) return i;
return -1;
}
int relabel(int u){
int tmp = inf;
for(int i = 1; i <= n; i ++)
if(c[u][i] > 0 && tmp > level[i] + 1)
tmp = level[i] + 1;
if(tmp == inf) tmp = n;
return tmp;
}
int sap(){
init_sap();
int flow = 0, u = s;
while(level[s] <= n){
int v = find_path(u);
if(v > 0){
pre[v] = u;
u = v;
if(u == t){
int min_flow = inf;
for(int i = t; i != s; i = pre[i])
if(min_flow > c[ pre[i]][i])
min_flow = c[ pre[i]][i];
for(int i = t; i != s; i = pre[i]){
c[pre[i]][i] -= min_flow;
c[i][pre[i]] += min_flow;
}
flow += min_flow;
u = s;
}
}else{
if(-- gap[ level[u]] == 0) return flow;
int v = relabel(u);
gap[v] ++;
level[u] = v;
if(u != s) u = pre[u];
}
}
return flow;
}
int main(){
while(~scanf("%d%d%d%d", &n, &np, &nc,& m)){
memset(c, 0, sizeof c);
s=n+1,t=n+1+1,n+=2;
//cout<<s<<endl;
for(int i = 1; i <= m; i ++){
int u, v, w;
scanf(" (%d,%d)%d", &u, &v, &w);
c[u+1][v+1] += w;
}
for(int i = 1; i <= np; i ++)
{
int v, w;
scanf(" (%d)%d", &v, &w);
c[s][v+1] = w;
}
for(int i = 1; i <=nc; i ++){
int u, w;
scanf(" (%d)%d", &u, &w);
c[u+1][t] = w;
}
/*for(int i=1;i<=n;i++)
{
cout<<endl;
for(int j=1;j<=n;j++)
cout<<c[i][j]<<' ';
}*/
int flow = sap();
printf("%d\n", flow);
}
return 0;
}