POJ - 2135
问题可以转化为求两条 1 1 1到 n n n的路径,使得这两条路径没有重边且费用和最小。而这个问题我们又可以转化为最小费用流问题。对于 u u u到 v v v的费用为 w w w双向边,在图中转化为 u u u到 v v v容量 1 1 1费用为 w w w的边和 v v v到 u u u容量为 1 1 1,费用为 w w w的边; 求 1 1 1到 n n n流量为 2 2 2的最小费用即可。
由网络流的意义可知,残留网络图中不会使双向边同时存在。
等效性证明:
对于在问题中的每一中方案都对应网络图中一个费用流,且每一个费用流都对应图中的一个方案。故这两个问题等效,所以我们求最小花费即求最小费用流。
#include
#include
#include
#include
#include
#include
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=1100;//顶点数量
const int inf=0x3f3f3f3f;
struct edge
{
int to,cap,cost,rev;
edge() {}
edge(int to,int cap,int cost,int rev)
{
this->to=to,this->cap=cap,this->cost=cost,this->rev=rev;
}
};
class MCMF
{
public:
vector<edge> adja[maxn];
int dis[maxn],prevv[maxn],preve[maxn],top;
bool inque[maxn];
void init(int n)
{
for(int i=0; i<=n; ++i) adja[i].clear();
top=n;
}
void addEdge(int u,int v,int f,int cost)
{
adja[u].push_back(edge(v,f,cost,adja[v].size()));
adja[v].push_back(edge(u,0,-1*cost,adja[u].size()-1));
}
bool spfa(int s,int t)
{
queue<int> mp;
mset(dis,inf);
mset(prevv,-1);
mset(inque,0);
mp.push(s),prevv[s]=s,dis[s]=0,inque[s]=true;
while(!mp.empty())
{
int u=mp.front();
mp.pop();
inque[u]=false;
for(int i=0; i<adja[u].size(); ++i)
{
edge& e=adja[u][i];
if(e.cap>0&&dis[e.to]>dis[u]+e.cost)
{
dis[e.to]=dis[u]+e.cost;
prevv[e.to]=u;
preve[e.to]=i;
if(!inque[e.to])
{
inque[e.to]=true;
mp.push(e.to);
}
}
}
}
if(~prevv[t]) return true;
return false;
}
//他的第三个函数也可以这样写,即满足流f的最小花费
int minCostMaxFlow(int s,int t,int f) //不能满足流f则返回-1
{
int cost=0;
while(f>0)
{
spfa(s,t);
if(dis[t]==inf)
return -1;
int d=f;
for(int v=t; v!=prevv[v]; v=prevv[v]) //找到d
d=min(d,adja[prevv[v]][preve[v]].cap);
cost+=d*dis[t];
f-=d;
for(int v=t; v!=prevv[v]; v=prevv[v])
{
edge &e=adja[prevv[v]][preve[v]];
e.cap-=d;
adja[v][e.rev].cap+=d;
}
}
return cost;
}
};
MCMF kit;
int main()
{
/*s:1,t:n 按给出的添加边,cap=1,容量为-1*/
int n,m;
while(~scanf("%d%d",&n,&m))
{
kit.init(n);
for(int i=1; i<=m; ++i)
{
int u,v,cost;
scanf("%d %d %d",&u,&v,&cost);
kit.addEdge(u,v,1,cost);
kit.addEdge(v,u,1,cost);
}
int ans=kit.minCostMaxFlow(1,n,2);
printf("%d\n",ans);
}
return 0;
}