欢迎访问我的Uva题解目录哦 https://blog.csdn.net/richenyunqi/article/details/81149109
给出一个v(3≤v≤1000)个点e(3≤e≤10000)条边的有向加权图,求1~v的两条不相交(除了起点和终点外没有公共点)的路径,使得权和最小。
参考《算法设计入门经典(第2版)》的提示:
把2到v-1的每个结点i拆成i和i’两个结点,中间连一条容量为1,费用为0的边,然后求1到v的流量为2的最小费用流即可。
我在这个提示的基础上做出了一些改善,我把1~v
所有的点都拆成了两个点,例如对编号为i
的点拆成了i
和i+v
两个点,连边的方法是:
1~1+v
、v~v+v
之间连一条容量为2、费用为0的边,表示这两个点最多可以经过2次2
到v-1
的每个结点i
拆成i和i+v
两个结点,中间连一条容量为1,费用为0的边,表示这些点最多可以经过1次a+v
到b
,容量为1,费用为c的边,表示这条边最多可以经过1次然后利用最小费用最大流的算法对这一网络进行求解即可。
每个测试点有多个测试样例
#include
using namespace std;
struct Edge{
int from,to,cap,flow,cost;
Edge(int f,int t,int c,int fl,int co):from(f),to(t),cap(c),flow(fl),cost(co){}
};
const int INF=0x3fffffff,MAXV=2005;//无穷大,结点最大个数
vector<Edge>edges;
vector<vector<int>>graph(MAXV);
int v,e;
void insertEdge(int id1,int id2,int cap,int cost){//插入边
graph[id1].push_back(edges.size());
edges.push_back(Edge(id1,id2,cap,0,cost));
graph[id2].push_back(edges.size());
edges.push_back(Edge(id2,id1,0,0,-cost));
}
bool BellmanFord(int s,int t,int&flow,long long&cost){//最大流算法,s为源点,t为汇点
int a[MAXV]={0},p[MAXV]={0},dis[MAXV]={0};//a数组表示源点到结点a[i]的残量,p数组表示最短路树上到达结点p[i]的边在edges数组中的序号
fill(dis,dis+MAXV,INF);
bool inQueue[MAXV]={false};
dis[s]=0;
inQueue[s]=true;
a[s]=INF;//起点的残量置为无穷大
queue<int>q;
q.push(s);
while(!q.empty()){//广度优先遍历查找从源点到达汇点的增广路
int u=q.front();
q.pop();
inQueue[u]=false;
for(int i:graph[u]){//遍历以x为起点的边
Edge&e=edges[i];
if(e.cap>e.flow&&dis[e.to]>dis[u]+e.cost){//当前边的终点的残量为0且容量大于流量
dis[e.to]=dis[u]+e.cost;
p[e.to]=i;//更新到达该终点的边的编号
a[e.to]=min(a[u],e.cap-e.flow);//更新源点到该终点的残量
if(!inQueue[e.to]){
inQueue[e.to]=true;
q.push(e.to);//压入队列
}
}
}
}
if(dis[t]==INF)
return false;
flow+=a[t];
cost+=dis[t]*1ll*a[t];
for(int u=t;u!=s;u=edges[p[u]].from){//从汇点向前遍历增广路经,更新每条增广路的流量
edges[p[u]].flow+=a[t];
edges[p[u]^1].flow-=a[t];
}
return true;
}
//需要保证初始网络中没有负权环
pair<int,long long> MinCostMaxFlow(int s,int t){
int flow=0;
long long cost=0;
while(BellmanFord(s,t,flow,cost));
return {flow,cost};
}
int main(){
while(~scanf("%d%d",&v,&e)&&v!=0){
edges.clear();
fill(graph.begin(),graph.end(),vector<int>());
insertEdge(1,1+v,2,0);
for(int i=2;i<v;++i)
insertEdge(i,i+v,1,0);
insertEdge(v,v+v,2,0);
for(int i=0;i<e;++i){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
insertEdge(a+v,b,1,c);
}
auto i=MinCostMaxFlow(1,v+v);
printf("%lld\n",i.second);
}
return 0;
}