/* 题意:有N个点的农场,之间有M条路径,问从起点走到到终点再走回起点的最短行走距离是多少,并且行走过程 中的路径不能有重复。 题解:最小费用最大流; 建图:建立无向图,边的权值均为1,保证路径只能走一次再分别加入源点和汇点,分别连接起点和终点,权值分 别为2,因为题目求的是一个来回的路径,亦即求从起点到终点的两条不重复路径即可。 从起点到终点再回起点其实是一个最大流的问题,由于还要使距离最短,因此在边加入一个值cost记录路径长度, 最小费用最大流求的是cost*权值的最小值,但是因为这个图中的所需求的权值均为1,因此直接用cost即可。最终 求最大流后将路径相加。 */ #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; #define EMAX 500000 #define VMAX 1200 const int INF = 0xfffffff; int head[VMAX],dis[VMAX],dist[VMAX],cur[VMAX],gap[VMAX],pre[VMAX],path[VMAX]; int EN; struct edge { int to; int weight; int cost; int next; }e[EMAX]; void insert(int u,int v,int w, int c) { e[EN].to = v; e[EN].weight = w; e[EN].cost = c; e[EN].next = head[u]; head[u] = EN++; e[EN].to = u; e[EN].weight = 0; e[EN].cost = -c; e[EN].next = head[v]; head[v] = EN++; } bool spfa(int start, int t) { memset(path,-1,sizeof(path)); memset(pre,-1,sizeof(pre)); bool vis[VMAX]; for(int i=0; i<=t; i++) { dist[i] = INF; vis[i] = false; } queue<int> Q; dist[start] = 0; vis[start] = true; Q.push(start); while (!Q.empty()) { int u = Q.front(); Q.pop(); for(int i=head[u]; i!=-1; i=e[i].next) { int v = e[i].to; if (e[i].weight && dist[u]+e[i].cost < dist[v]) { pre[v] = u; path[v] = i; dist[v] = dist[u]+e[i].cost; if (!vis[v]) { Q.push(v); vis[v] = true; } } } vis[u] = false; } if (dist[t] == INF) return false; return true; } int mcmf(int s, int t)//最小费用最大流 { queue<int> Q; int ret = 0; int maxflow = 0; while (spfa(0,t))//每次通过spfa求最短的允许路 { ret += dist[t]; int mw = -1; for(int v=t; v!=s; v=pre[v])//找出当前路径中的流量的最小容量 { if (mw == -1 || mw > e[path[v]].weight) mw = e[path[v]].weight; } for(int v=t; v!=s; v=pre[v])//修改路径的容量,求出残余网络 { e[path[v]].weight -= mw; e[path[v]^1].weight += mw;//更新逆向边 } maxflow += mw; } return ret; } int main(void) { int m,n,a,b,l; while (~scanf("%d%d",&n,&m)) { memset(head,-1,sizeof(head)); EN = 0; for(int i=0; i<m; i++) { scanf("%d%d%d",&a,&b,&l); insert(a,b,1,l); insert(b,a,1,l); } insert(0,1,2,0); insert(n,n+1,2,0); printf("%d\n",mcmf(0,n+1)); } return 0; }