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\n",min_cost_flow(S,T,2)); } return 0; }
版权声明:本文博主原创文章,博客,未经同意不得转载。