乍一看题目,这特喵的怎么能扯上MCMF?
乍一又思索,其实好像也是可以的样子......PS:我不会告诉你其实solution是EM。
读入的每条边的长度作为费用,将每条边的流量设为1,这样就能限制每条边只走一次啦~那么问题来了,怎样保证只走两条边呢?于是我们再连一条0->1和n->n+1的流量都为2的边,并且程序从0做到n+1,于是此题就完美转化为了MCMF。
猛戳此处学习MCMF→_→:http://blog.csdn.net/ycdfhhc/article/details/42586349
另外,这题是无向图,所以建图的时候要注意:正反方向均要加边,否则两条边的费用都是正的,退回时无法修复费用。
具体情况参看代码:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int maxv=10005;//poj真的是非常坑......说好的n<1000 m<10000结果tmd硬是RE了......ORZ
const int maxe=100005;
int dist[maxv],pre[maxv],n,m,ans,head[maxv],tot;
struct typ{
int u,v,flow,cost,next;
}edge[maxe];
void add(int u,int v,int c,int cost){ //数组模拟指针什么的不会的童鞋自己搞去
edge[tot].u=u;edge[tot].v=v;edge[tot].cost=cost;
edge[tot].flow=c;edge[tot].next=head[u];head[u]=tot++;
edge[tot].u=v;edge[tot].v=u;edge[tot].cost=-cost;
edge[tot].flow=0;edge[tot].next=head[v];head[v]=tot++;
}
bool spfa(){
int now,next,q[maxv*10],l,r;bool vis[maxv];
l=r=0;
memset(vis,0,sizeof vis);vis[0]=1;
memset(pre,-1,sizeof pre);
memset(dist,10,sizeof dist);dist[0]=0;
while(l<=r){
now=q[l];vis[now]=0;
for(int i=head[now];i!=-1;i=edge[i].next){
if(edge[i].flow>0){
next=edge[i].v;
if(dist[next]>dist[now]+edge[i].cost){
dist[next]=dist[now]+edge[i].cost;
pre[next]=i;
if(!vis[next]){
vis[next]=true;
q[++r]=next;
}
}
}
}
l++;
}
return dist[n+1]!=168430090;//memset中的10等于实际168430090 见line27
}
void init(){
tot=0;int x,y,z;
memset(head,-1,sizeof(head));
add(0,1,2,0);add(n,n+1,2,0);
for (int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,1,z); //正反方向都要加边
add(y,x,1,z);
}
}
int main(){
freopen("a.in","r",stdin);
while (~scanf("%d%d",&n,&m)){
init();
while (spfa()){
for (int i=pre[n+1];i!=-1;i=pre[edge[i].u]){
edge[i].flow--;
edge[i^1].flow++;
}
ans+=dist[n+1];
}
cout<<ans<<endl;
}
return 0;
}
部分思路参考http://www.cnblogs.com/markliu/archive/2012/05/22/2513791.html