// 最小费用最大流
struct MCMF
{
struct node
{
int vi,id,wi,ci;
};
const int inf = 0x3f3f3f3f;
int S,T,mxflow,cost;
std::vector<int> dis,to,cur;
std::vector<bool> vis;
std::vector<std::vector<node>> r;
MCMF(int n,int s,int t) : dis(n + 10),vis(n + 10),r(n + 10),cur(n + 10),S(s),T(t),mxflow(0),cost(0){}
int spfa()//spfa代替bfs寻找增广路
{
std::fill(dis.begin(), dis.end(), inf);
std::fill(vis.begin(), vis.end(), 0);
queue<int> q;
q.push(S);dis[S] = 0;
while(q.size())
{
int x = q.front();q.pop();
vis[x] = 0;//vis用于判断节点是否在队列中,若在,则最短路更新时不需重复加入队列
for(auto tmp:r[x])
{
if(tmp.wi && dis[x] + tmp.ci < dis[tmp.vi])
{
dis[tmp.vi] = dis[x] + tmp.ci;
if(!vis[tmp.vi])
q.push(tmp.vi),vis[tmp.vi] = 1;
}
}
}
if(dis[T] == inf)
return 0;
return 1;
}
int dfs(int x,int fl)
{
if(x == T)
return fl;
vis[x] = 1;//此处vis用于判断节点是否在目前选择的增广路上,若在,则不能重复加入。因为例题路径可能有0环存在
int rem = fl;
for(int i = 0;i < r[x].size();i ++)
{
if(rem == 0)
break;
int vi = r[x][i].vi,wi = r[x][i].wi,ci = r[x][i].ci;
if(dis[x] + ci == dis[vi] && wi && !vis[vi])
{
int flow = dfs(vi,min(rem,wi));//找到可行流
if(flow > 0)
{
rem -= flow;
r[x][i].wi -= flow;
r[vi][r[x][i].id].wi += flow;
cost += ci*flow;//计算费用
if(rem <= 0)
break;
}
}
}
vis[x] = 0;//撤销点,看看能不能继续找到一条增广路
if(fl == rem)
dis[x] = inf;//如果从x点出发找不到可行流,则不再找x这个点
return fl - rem;
}
void addEdge(int u,int v,int w,int c)//vector存图
{
r[u].push_back({v,(int)r[v].size(),w,c});
r[v].push_back({u,(int)r[u].size() - 1,0,-c});
}
void Mxflow()//费用流
{
while(spfa())
{
for(auto &v:cur)
v = 0;
mxflow += dfs(S,inf);
}
//printf("%d %d\n",mxflow,cost);
}
};