最小费用流最大流+模板+poj2135

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wuxiaowu547/article/details/81989870

http://poj.org/problem?id=2135

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
#define M 1100
const int inf=0x7fffffff;
struct node
{
    int u,v,c,f,next;  //C为花费,F为flow流量
} e[M*40];
int pre[M],dis[M],head[M],t;
int vis[M];
void add1(int u,int v,int c,int f)
{
    e[t].u=u;
    e[t].v=v;
    e[t].c=c;
    e[t].f=f;
    e[t].next=head[u];
    head[u]=t++;
}
void add(int u,int v,int c,int f)
{
    add1(u,v,c,f);
    add1(v,u,-c,0);  //反向边流量初始为零,如果走反向边费用正好和原边抵消
}
int spfa(int s,int t)
{
    int i,u,v;
    queue<int>q;
    q.push(s);
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    for(i=s; i<=t; i++)
        dis[i]=inf;
    dis[s]=0;
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        for(i=head[u]; i!=-1; i=e[i].next)
        {
            v=e[i].v;
            if(e[i].f&&dis[v]>dis[u]+e[i].c)  //找到一条最小费用流
            {
                dis[v]=dis[u]+e[i].c;
                pre[v]=i;       //记录路径
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
        vis[u]=0;
    }
    if(dis[t]!=inf)
        return 1;
    return 0;
}
void solve(int s,int t)
{
    int ans=0,i,j;
    int flow=0,cost=0;     //总流量、总费用
    while(spfa(s,t))
    {
        int minf=inf;
        for(i=pre[t]; i!=-1; i=pre[e[i].u])
        {
            if(e[i].f<minf)
                minf=e[i].f;
        }
        flow+=minf;   //该条路径的流量
        for(i=pre[t]; i!=-1; i=pre[e[i].u])
        {
            j=i^1;
            e[i].f-=minf;
            e[j].f+=minf;
        }
        cost+=dis[t]*minf;   //单位运费和乘以流量得费用
    }
    printf("%d\n",cost);
}
int main()
{
    int i,u,v,c,n,m;
    while(scanf("%d%d",&n,&m)!=-1)
    {
        t=0;
        memset(head,-1,sizeof(head));
        for(i=0; i<m; i++)
        {
            scanf("%d%d%d",&u,&v,&c);  //边长度看做单位运费
            add(u,v,c,1);
            add(v,u,c,1);       //无向边,费用为长度,流量为1(只能通过一次)
        }
//往返的两条线路可以看成是从源点到汇点的两条线路,
//所以只要从附加源点向源点连一条容量为2的边和从汇点向附加汇点连一条容量为2的边就可以限线路为两条.
        add(0,1,0,2);
        add(n,n+1,0,2);
        solve(0,n+1);
    }

}

猜你喜欢

转载自blog.csdn.net/wuxiaowu547/article/details/81989870
今日推荐