zoukankan      html  css  js  c++  java
  • POJ Farm Tour

                                                                            Farm Tour

     

    题目:

       约翰有N块地,家在1号,而N号是个仓库。农场内有M条道路(双向的),道路i连接这ai号地和bi号地,长度为ci。

    约翰希望依照从家里出发,经过若干地后达到仓库。然后再返回家中。假设要求往返不能经过同一条道路两次,求參观路线总长度最小值。

     

    算法分析:

       用最短路求解然后在删除第一次最短路中的边在求解一次最短路。这样是否可行?应该立即就能找到反例证明该方法不能总得到最优结果吧。

        于是我们放弃把问题当作去和回的这样的想法,转而将问题当作求从1号顶点到N号顶点的两条没有公共边的路径有怎样?这样转换之后。不就是求流量为2的最小费用了,由于道路是双向的。

     

    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    
    /*
        
        流量限制为f下。求解最小费用
        时间复杂度:O(F mlogn)
        
    
    */
    typedef pair<int,int> P;
    const int INF = 1 << 30;
    const int MAXN = 1000 + 10;
    
    struct Edge{
       int to,cap,cost,rev;
       Edge(){};
       Edge(int _to,int _cap,int _cost,int _rev)
           :to(_to),cap(_cap),cost(_cost),rev(_rev){};
    };
    
    int V;        //顶点
    int N,M,S,T;
    vector<Edge> G[MAXN];
    int h[MAXN];     //顶点的势
    int dist[MAXN];  //最短距离
    int prevv[MAXN],preve[MAXN];  //最短路中德前驱节点和相应的边
    
    void init(){
       S = 1; T = N; V = T + 1;
       for(int i = 0;i <= V;++i)
         G[i].clear();
    }
    
    
    //从图中添加一条从from到to容量为cap费用为cost的边
    void addEdge(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() - 1));
    }
    
    //求解从s到t流量为f的最小费用流
    //假设没有流量为f的流。则返回-1
    int min_cost_flow(int s,int t,int f){       //s:起点 t:终点 f:流量限制
        int res = 0;
        fill(h,h + V,0);            //初始化h
        while(f > 0){
                
            //使用Dijkstra算法更新h
            priority_queue<P,vector<P>,greater<P> > Q;
            fill(dist,dist + V,INF);
            dist[s] = 0;
            Q.push(P(0,s));
            while(!Q.empty()){
                P p = Q.top(); Q.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];
                    int tmp = dist[v] + e.cost + h[v] - h[e.to];
                    if(e.cap > 0 && dist[e.to] > tmp){
                        dist[e.to] = tmp;
                        prevv[e.to] = v;
                        preve[e.to] = i;
                        Q.push(P(dist[e.to],e.to));
                    }
                } 
            }   //while
            
            //不能增广
            if(dist[t] == INF){
                return -1;
            }
            for(int v = 1;v <= V;++v) h[v] += dist[v];
            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 main()
    {
       //freopen("Input.txt","r",stdin);
    
        while(~scanf("%d%d",&N,&M)){
            init();
            int a,b,c;
            for(int i = 0;i < M;++i){
                scanf("%d%d%d",&a,&b,&c);
                addEdge(a,b,1,c);
                addEdge(b,a,1,c);
            }
            printf("%d
    ",min_cost_flow(S,T,2));
        }
        return 0;
    }
    
    
    
    
    
    


     

    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    MySQL语句创建表、插入数据遇到的问题-20/4/18
    【Navicat】MySQL 8.0.17 数据库报2059错误
    MySQL 8.0.17 版安装 || Windows
    C#--Invoke和BeginInvoke用法和区别
    C#--params关键字
    C#--typeof() 和 GetType()区别
    C#--利用反射编写的SqlHelper类
    C#--反射基础
    C#--LINQ--2--LINQ高级查询
    C#--LINQ--1--初学LINQ基础和查询
  • 原文地址:https://www.cnblogs.com/hrhguanli/p/4876805.html
Copyright © 2011-2022 走看看