/*
题意:n个地点有m条路相连,从1走到n再回来,不走重复的路(这题居然认为,同一条路,按不同的方向走算是走不重复的路)
最小费用最大流
因为要来回,素以相当于找两条1~n的最短路
s~1 流量2 费用0
n~t 流量2 费用0
是每条无向边都拆分成两条有向边
把有向边分别加到图里(还有他的退边,反费用,流量0)
退边和他的反向边的表示是一样的,但是费用和流量是不一样的,所以不可以用邻接矩阵,只能用邻接表了
*/
#include<iostream>
#include<queue>
using namespace std;
const int inf = 0x7fffffff;
const int en = 40010;
const int vn = 1005;
int n,m,mincost,s,t;
int pre[vn],vis[vn],dist[vn];//求最短路径的时候用到的 pre保存流向他的那个边的编号 vis访问标志 dist距离
struct edge//边
{
int u[en],v[en],f[en],c[en],head[en],yong,next[en];//边的前端和后端 流量 费用 邻接表的头 分配记录 下一条边
edge()//初始化
{
clear();
}
void clear()//清除 除 head外 其他的都是主动写入的故不用清除
{
yong=1;
memset(head,0,sizeof(head));
}
void adde(int uu,int ww,int cost,int flow)//加一条边 加他自己和他的退边
{
add(uu,ww,cost,flow);
add(ww,uu,-cost,0);
}
void add(int uu,int ww,int cost,int flow) //加边
{
u[yong]=uu;
v[yong]=ww;
f[yong]=flow;
c[yong]=cost;
next[yong]=head[uu];
head[uu]=yong;
yong++;
}
}e;
int min(int a,int b)
{
return a<b?a:b;
}
int spfa()//求最短路径
{
int i,u,v,p;
memset(vis,0,sizeof(vis));
memset(pre,0,sizeof(dist));
queue<int>q;
q.push(s);
vis[s]=1;
for(i=1;i<=t;++i)
dist[i]=inf;
dist[s]=0;
while(!q.empty())
{
u=q.front();
for(p=e.head[u];p;p=e.next[p])
{
v=e.v[p];
if(e.f[p]&&dist[v]>dist[u]+e.c[p])
{
dist[v]=dist[u]+e.c[p];
pre[v]=p;//记录流向v的那条边的编号 方便后面压入流
if(!vis[v])
{
q.push(v);
vis[v]=1;
}
}
}
q.pop();
vis[u]=0;
}
if(dist[t]==inf)
return 0;
return 1;
}
void addf()//压入流
{
int i,j;
i=pre[t];
while(i!=0)
{
if(i%2)//求边i的退边 之前看别人的代码,直接用了 i^1 结果老是错 人家是从 0 开始用的 我是从1开始用的 所以这里处理一下
j=i+1;
else j=i-1;
e.f[i]--;
e.f[j]++;
mincost+=e.c[i];
i=pre[e.u[i]];
}
return;
}
int main()
{
int i,u,v,c;
cin>>n>>m;
mincost=0;
s=0;
t=n+1;
for(i=1;i<=m;++i)
{
cin>>u>>v>>c;
e.adde(u,v,c,1);
e.adde(v,u,c,1);
}
e.adde(s,1,0,2);
e.adde(n,t,0,2);
while(spfa())
addf();
cout<<mincost<<endl;
return 0;
}