给定有向图,起点和终点。起点有2艘船,分别沿不同的路,走到终点,不仅路径不能重合,除起点终点,不能经过相同的点。(即结点容量为1)
求2条路径的最小费用。
1.结点容量问题可以用拆点法。
将点i边成i和i’,i和i‘之间连接一条容量为1,费用为0的路径即可。
2.只求2条路径。
所以不能直接while(bellmanford()) ;这样会找到所有增广路径,求出最大流下的最小费用。
但是这题只需要流量为2时的最小费用,所以for(int i = 0;i < 2;i ++) belmanford();找2次即可。
并且源头的流量a[s] = 1,各路径的容量也设为1好了。
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
const int maxn = 2000 + 5;
const int INF = 1 << 30;
typedef long long ll;
struct edge{
int u,v,flow,cap,cost;
};
struct MCMF{
int n,m;
vector<edge> es;
vector<int> mp[maxn];
int a[maxn];
int p[maxn];
bool inq[maxn];
int d[maxn];
void init(int n){
this->n = n;
es.clear();
for(int i = 1;i <= n;i ++) mp[i].clear();
}
void addedge(int u,int v,int cap,int cost){
es.push_back({u,v,0,cap,cost});
es.push_back({v,u,0,0,-cost});
m = es.size();
mp[u].push_back(m - 2);
mp[v].push_back(m - 1);
}
bool bellmanford(int s,int t,ll &cost,int &flow)//这里没有判断负环的。当达到最大流时,形成最小割,返回false。此时的费用就是最小的
{
memset(inq, 0, sizeof(inq));
memset(a, 0, sizeof(a));
for(int i = 0;i < n;i ++) d[i] = INF;
d[s] = 0;a[s] = 1;p[s] = -1;//不用设置s的pre吧
queue<int> q;
q.push(s);inq[s] = true;
while(!q.empty())
{
int x = q.front();q.pop();
inq[x] = false;
for(int i = 0;i < mp[x].size();i ++)
{
edge &e = es[mp[x][i]];
if(e.cap > e.flow && d[e.v] > d[e.u] + e.cost)
{
d[e.v] = d[e.u] + e.cost;
p[e.v] = mp[x][i];
a[e.v] = min(a[e.u],e.cap - e.flow);
if(!inq[e.v]) { q.push(e.v);inq[e.v] = true;}
}
}
}
if(d[t] == INF) return false;
flow += a[t];
cost += (ll)d[t];
for(int u = t;u != s; u = es[p[u]].u)
{
es[p[u]].flow += a[t];
es[p[u] ^ 1].flow -= a[t];
}
return true;
}
int MinCostMaxFlow(int s,int t,ll &cost)//没有判断负环。
{
int flow = 0;
for(int i = 0;i < 2;i ++) bellmanford(s, t, cost, flow);//只用找2条路,所以每次a[s] = 1开始增广,增广2次即可
return flow;
}
};
int main()
{
int n,m;
while (scanf("%d%d",&n,&m) != EOF) {
MCMF mcmf;
mcmf.init(2 * n);
int s = 1,t = n;
int u,v,cost;
for (int i = 0; i < m; i ++) {
scanf("%d%d%d",&u,&v,&cost);
if(1 < u && u < n) u += n;
mcmf.addedge(u,v, 1, cost);//
}
for (int i = 2; i < n; i ++) {
mcmf.addedge(i, i + n, 1, 0);
}
ll sum_cost = 0;
mcmf.MinCostMaxFlow(s, t,sum_cost);
printf("%lld\n",sum_cost);
}
return 0;
}