Problem : Farm Tour
Description : FJ想带他的朋友参观农场,他从家里出发,到达他在农场的休息点后返回,每一条路都有距离,他希望两次走的路程不一样,但是所走的总距离最小。
Solution : 最小费用最大流问题。FJ从家里出发到达休息点后返回,可以转化为从家里到休息点有两条不同的路,路径不同,但所走的路程为最短。定义一个源点到家的流量为2,费用为0;再定义一个汇点,休息点到汇点的流量也为2,费用为0,其他的路径则流量为1,费用为路径长度。
Code (C++) :
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define N 1020
#define inf 0x3f3f3f3f
using namespace std;
int visit[N],n,t=0;
int dis[N];
int head[N];
int pre[N];
struct edge
{
int u;
int v;
int cost; //费用
int cap; //总流量
int flow; //已经流过的流量
int next;
edge() {}
edge(int u,int v,int cost,int cap,int flow,int next)
{
this->u=u;
this->v=v;
this->cost=cost;
this->cap=cap;
this->flow=flow;
this->next=next;
}
} e[N*N];
void addedge(int u,int v,int cap,int c)
{
e[t]=edge(u,v,c,cap,0,head[u]);
head[u]=t++;
e[t]=edge(v,u,-c,0,0,head[v]);
head[v]=t++;
}
bool Spfa(int src,int des)
{
int u,v,weight;
memset(visit,0,sizeof(visit));
memset(dis,inf,sizeof(dis));
memset(pre,-1,sizeof(pre));
dis[src]=0;
queue<int>q;
while(!q.empty())
q.pop();
q.push(src);
visit[src]=1;
while(!q.empty())
{
u=q.front();
q.pop();
visit[u]=0;
for(int i=head[u]; i!=-1; i=e[i].next)
{
v=e[i].v;
weight=e[i].cost;
if(e[i].cap>e[i].flow&&dis[v]>dis[u]+weight)
{
dis[v]=dis[u]+weight;
pre[v]=i;
if(!visit[v])
{
q.push(v);
visit[v]=1;
}
}
}
}
if(pre[des]==-1)
return false;
else
return true;
}
//返回值是最大流 cost中存的是最小费用
int minCostMaxflow(int src,int des,int &cost)
{
int flow=0;
cost=0;
while(Spfa(src,des))
{
int Min=inf;
for (int i=pre[des]; i!=-1; i=pre[e[i^1].v])
{
if (Min>e[i].cap-e[i].flow)
Min=e[i].cap-e[i].flow;
}
for (int i=pre[des]; i!=-1; i=pre[e[i^1].v])
{
e[i].flow+=Min;
e[i ^ 1].flow-=Min;
cost+= e[i].cost*Min;
}
flow+=Min;
}
return flow;
}
int main()
{
//freopen("in.txt","r",stdin);
int m,u,v,f;
while(cin>>n>>m)
{
int ans=0;
memset(head,-1,sizeof(head));
for(int i=0;i<m;i++)
{
cin>>u>>v>>f;
addedge(u,v,1,f);
addedge(v,u,1,f);
}
addedge(0,1,2,0);
addedge(n,n+1,2,0);
minCostMaxflow(0,n+1,ans);
cout<<ans<<endl;
}
return 0;
}