POJ 2135 Farm Tour

来源:互联网 发布:淘宝上怎么换货流程 编辑:程序博客网 时间:2024/06/05 05:07

题意:有n块地,m条路,道路i连接着ai号地和bi号地,长度为ci。要从第1块地走到第n块地再走回第1块地,要求往返不能经过同一条道路两次,求路线总长度的最小值

解题思路:最小费用流.如果只考虑去或者回的情况,那么问题就是无向图中的最短路问题,但现在既要去又要回,并且不能经过相同的道路,所以求去时的最短路和回来时的最短路就不行了。这里要放弃把问题当作去和回的想法,转而将问题当作求从1号顶点到n号顶点的两条没有公共边的路径,这样转化之后就是求最小费用流了。要设置一个源点和一个汇点,把每条边的流量设为1,把从源点发出的流量和汇点接收的流量设为2(因为找两条路),这样就是求从源点到汇点流量为2的最小费用流了

代码:

#include <iostream>#include <algorithm>#include <cstring>#include <string>#include <cstdio>#include <cmath>#include <vector>#include <queue>using namespace std;#define INF 0x3f3f3f3ftypedef pair<int,int> P;//first保存最短距离,second保存顶点编号//用于表示边的结构体(终点、容量、费用、反向边)struct edge{    int to,cap,cost,rev;};int V,E;vector<edge> G[1005];//图的邻接表表示int h[1005];//顶点的势int dist[1005];//最短距离int prevv[1005],preve[1005];//最短路中的前驱结点和对应的边//向图中增加一条从from到to容量为cap费用为cost的边void add_edge(int from,int to,int cap,int cost){    G[from].push_back((edge){to,cap,cost,G[to].size()});    G[to].push_back((edge){from,0,-cost,G[from].size()});}//求解从s到t费用为f的最小费用流//如果没有流量为f的流,就返回-1int min_cost_flow(int s,int t,int f){    int res=0;    fill(h,h+V,0);//初始化h    while(f>0)    {        //用dijkstra算法更新h        priority_queue<P,vector<P>,greater<P> > que;        fill(dist,dist+V,INF);        dist[s]=0;        que.push(P(0,s));        while(!que.empty())        {            P p=que.top();que.pop();            int v=p.second;            if(dist[v]<p.first)continue;            for(int i=0;i<G[v].size();i++)            {                edge &e=G[v][i];                if(e.cap>0&&dist[e.to]>dist[v]+e.cost+h[v]-h[e.to])                {                    dist[e.to]=dist[v]+e.cost+h[v]-h[e.to];                    prevv[e.to]=v;                    preve[e.to]=i;                    que.push(P(dist[e.to],e.to));                }            }        }        if(dist[t]==INF)return -1;//不能再增广        for(int v=0;v<V;v++)h[v]+=dist[v];        //沿s到t的最短路尽量增广        int d=f;        for(int v=t;v!=s;v=prevv[v])        {            d=min(d,G[prevv[v]][preve[v]].cap);        }        f-=d;        res+=d*h[t];        for(int v=t;v!=s;v=prevv[v])        {            edge &e=G[prevv[v]][preve[v]];            e.cap-=d;            G[v][e.rev].cap+=d;        }    }    return res;}int a[10005],b[10005],c[10005];int main(){    while(scanf("%d%d",&V,&E)==2)    {        for(int i=0;i<E;i++)        {            scanf("%d%d%d",&a[i],&b[i],&c[i]);        }        //建图        int s=0,t=V-1;//源点、汇点        for(int i=0;i<E;i++)        {            add_edge(a[i]-1,b[i]-1,1,c[i]);            add_edge(b[i]-1,a[i]-1,1,c[i]);        }        printf("%d\n",min_cost_flow(s,t,2));    }    return 0;}


原创粉丝点击