标签:最小费用流 open bsp \n continue 技术分享 hide 最大 alt
题目大意:
给定一个n个点m条边的无向图
求从点1去点n再从点n回点1的不重叠(同一条边不能走两次)的最短路
挑战P239
求去和回的两条最短路很难保证不重叠
直接当做是由1去n的两条不重叠的最短路
这样就变成了由1去n流量为2的最小费用流
#include <bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; const int N=1005; int n,m; struct EDGE { int v,w,c,r; }; vector <EDGE> E[N]; void addE(int u,int v,int w,int c) { E[u].push_back((EDGE){v,w,c,E[v].size()}); E[v].push_back((EDGE){u,0,-c,E[u].size()-1}); } int dis[N], pv[N] ,pe[N]; int minCFlow(int s,int t,int f) { int res=0; while(f>0) { /// Bellman-Ford求s到t最短路 memset(dis,INF,sizeof(dis)); memset(pv,0,sizeof(pv)); dis[s]=0; bool upD=1; while(upD) { upD=0; for(int i=0;i<=n;i++) { // 通过i点 if(dis[i]==INF) continue; for(int j=0;j<E[i].size();j++) { // 更新E[i][j]点的最短路 EDGE& e=E[i][j]; if(e.w>0 && dis[e.v]>dis[i]+e.c) { // 边容量>0才能走 dis[e.v]=dis[i]+e.c; // 找到更短的路 更新 pv[e.v]=i, pe[e.v]=j; // 记录前驱点及边 便于通过e.v找到i点 upD=1; } } } } if(dis[t]==INF) return -1; // s不能到t 不能增广 int d=f; // 找到本轮实际能够流出的流量(即实际用掉的容量) for(int i=t;pv[i];i=pv[i]) d=min(d,E[pv[i]][pe[i]].w); f-=d; // 容量消耗 res+=d*dis[t]; // 计算本轮花费 for(int i=t;pv[i];i=pv[i]) { EDGE& e=E[pv[i]][pe[i]]; e.w-=d; E[i][e.r].w+=d; } // 更新边的容量 } return res; } int main() { while(~scanf("%d%d",&n,&m)) { int s=1, t=n; for(int i=0;i<m;i++) { int u,v,c; scanf("%d%d%d",&u,&v,&c); addE(u,v,1,c); addE(v,u,1,c); // 建立u到v容量大小为1费用为c的边 } printf("%d\n",minCFlow(s,t,2)); // 求s到t传输大小为2(即最大容量为2)的最小费用流 } return 0; }
标签:最小费用流 open bsp \n continue 技术分享 hide 最大 alt
原文地址:https://www.cnblogs.com/zquzjx/p/10153650.html