/*都是找两条最短路,不能有相同的路径
第一题是有向图,需要拆点,第二题是无向图,不需要拆点
*/
/*A
算法思想
采用贪心的思想,每次找到一条从源点到达汇点的路径,增加流量,且该条路径满足使得增加的流量的花费最小,
直到无法找到一条从源点到达汇点的路径,算法结束。
由于最大流量有限,每执行一次循环流量都会增加,因此该算法肯定会结束,且同时流量也必定会达到网络的最大流量;
同时由于每次都是增加的最小的花费,即当前的最小花费是所有到达当前流量flow时的花费最小值,因此最后的总花费最小。
求解步骤
(1)找到一条从源点到达汇点的“距离最短”的路径,“距离”使用该路径上的边的单位费用之和来衡量。
(2)然后找出这条路径上的边的容量的最小值f,则当前最大流max_flow扩充f,同时当前最小费用min_cost扩充 f*min_dist(s,t)。
(3)将这条路径上的每条正向边的容量都减少f,每条反向边的容量都增加f。
(4)重复(1)--(3)直到无法找到从源点到达汇点的路径。
https://www.cnblogs.com/gtarcoder/p/4890739.html
*/
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int MAXN=2500;
const int INF=0x3f3f3f3f;
struct Edge
{
int from,to,cap,flow,cost;
Edge(){}
Edge(int f,int t,int c,int fl,int cs):from(f),to(t),cap(c),flow(fl),cost(cs){}
};
struct MCMF
{
int n,m,s,t;
int inq[MAXN];
int d[MAXN];
int p[MAXN];
int a[MAXN];
vector<Edge>edges;
vector<int> G[MAXN];
void init(int n) //n为结点个数
{
this->n=n;
edges.clear();
for(int i=0;i<n;++i)
G[i].clear();
}
void AddEdge(int from,int to,int cap,int cost)
{
edges.push_back(Edge(from,to,cap,0,cost));
edges.push_back(Edge(to,from,0,0,-cost)); //反向弧上的flow都是非正的 <=cap
int m=edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool spfa(int s,int t,int &flow,int &cost)
{
for(int i=0;i<n;++i) d[i]=INF;
memset(inq,0,sizeof(inq));
d[s]=0;
p[s]=0;
a[s]=INF;
inq[s]=1;
queue<int>q;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
inq[u]=0;
for(int i=0;i<G[u].size();++i)
{
Edge &e=edges[G[u][i]];
if(e.cap>e.flow&&d[e.to]>d[u]+e.cost)
{
d[e.to]=d[u]+e.cost;
p[e.to]=G[u][i]; //记录上一条边的编号
a[e.to]=min(a[u],e.cap-e.flow);
if(!inq[e.to])
{
q.push(e.to);
inq[e.to]=1;
}
}
}
}
if(d[t]==INF) return false;
flow+=a[t];
cost+=a[t]*d[t]; //t到s的最短路
int u=t;
while(u!=s)
{
edges[p[u]].flow+=a[t];
edges[p[u]^1].flow-=a[t];
u=edges[p[u]].from;
}
return true;
}
int MinCost(int s,int t)
{
int flow=0,cost=0;
while(spfa(s,t,flow,cost));
return cost;
}
}mc;
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
mc.init(2*n+2);
for(int i=2;i<=n-1;++i) //
mc.AddEdge(i,n+i,1,0);
for(int i=1;i<=m;++i)
{
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
if(u!=1 &&u!=n) mc.AddEdge(n+u,v,1,c); //注意点1,n不用拆
else mc.AddEdge(u,v,1,c);
}
mc.AddEdge(0,1,2,0);
mc.AddEdge(n,2*n+1,2,0);
int ans=mc.MinCost(0,2*n+1);
printf("%d\n",ans);
}
return 0;
}
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int MAXN=250;
const int INF=0x3f3f3f3f;
struct Edge
{
int from,to,cap,flow,cost;
Edge(){}
Edge(int f,int t,int c,int fl,int cs):from(f),to(t),cap(c),flow(fl),cost(cs){}
};
struct MCMF
{
int n,m,s,t;
int inq[MAXN];
int d[MAXN];
int p[MAXN];
int a[MAXN];
vector<Edge>edges;
vector<int> G[MAXN];
void init(int n) //n为结点个数
{
this->n=n;
edges.clear();
for(int i=0;i<n;++i)
G[i].clear();
}
void AddEdge(int from,int to,int cap,int cost)
{
edges.push_back(Edge(from,to,cap,0,cost));
edges.push_back(Edge(to,from,0,0,-cost)); //反向弧上的flow都是非正的 <=cap
int m=edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool spfa(int s,int t,int &flow,int &cost)
{
for(int i=0;i<n;++i) d[i]=INF;
memset(inq,0,sizeof(inq));
d[s]=0;
p[s]=0;
a[s]=INF;
inq[s]=1;
queue<int>q;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
inq[u]=0;
for(int i=0;i<G[u].size();++i)
{
Edge &e=edges[G[u][i]];
if(e.cap>e.flow&&d[e.to]>d[u]+e.cost)
{
d[e.to]=d[u]+e.cost;
p[e.to]=G[u][i]; //记录上一条边的编号
a[e.to]=min(a[u],e.cap-e.flow);
if(!inq[e.to])
{
q.push(e.to);
inq[e.to]=1;
}
}
}
}
if(d[t]==INF) return false;
flow+=a[t];
cost+=a[t]*d[t]; //t到s的最短路
int u=t;
while(u!=s)
{
edges[p[u]].flow+=a[t];
edges[p[u]^1].flow-=a[t];
u=edges[p[u]].from;
}
return true;
}
int MinCost(int s,int t,int &flow)
{
int cost=0; //忘记初始化不可饶恕啊
while(spfa(s,t,flow,cost));
return cost;
}
}mc;
int main()
{
int n;
while(scanf("%d",&n)&&n)
{
mc.init(n+2);
mc.AddEdge(0,1,2,0);
int m;
scanf("%d",&m);
for(int i=1;i<=m;++i)
{
int u, v, cost;
scanf("%d%d%d",&u,&v,&cost);
mc.AddEdge(u,v,1,cost);
mc.AddEdge(v,u,1,cost);
}
mc.AddEdge(n,n+1,2,0);
int flow=0;
int cost=mc.MinCost(0,n+1,flow);
if(flow<=1)
{
printf("Back to jail\n");
continue;
}
printf("%d\n",cost);
}
return 0;
}