最小费用流

来源:互联网 发布:windows curl 安装 编辑:程序博客网 时间:2024/04/29 04:52

单向图

#include<cstdio>//每次找费用的最短路,更新残留网络图直到找不到最短路为止#include<cstring>//最大费用  权值取负值  结果取负值#include<iostream>#include<algorithm>#include<queue>using namespace std;const int inf=0x3f3f3f3f;struct Node{    int u,v,w,cost,next;}node[1001000];int head[1001000],cont,sumflow;int vis[101000],dist[101000];int pre[101000];void init(){    cont=0;    sumflow=0;    memset(head,-1,sizeof(head));}void add(int u,int v,int w,int cost)//建图{    int i;    for(i=head[u]; i!=-1; i=node[i].next)//去重边    {        if(node[i].v==v)        {            if(node[i].cost>cost)//更新重边的费用                node[i].cost=cost,node[i^1].cost=-cost;            return ;        }    }    node[cont].u=u,node[cont].v=v;    node[cont].w=w,node[cont].cost=cost;    node[cont].next=head[u],head[u]=cont++;    node[cont].u=v,node[cont].v=u;    node[cont].w=0,node[cont].cost=-cost;//反向边费用为负的    node[cont].next=head[v],head[v]=cont++;}int SPFA(int st,int ed)//寻找最短路{    queue<int> q;    //memset(vis,0,sizeof(vis));//数组太大容易超时    //memset(pre,-1,sizeof(pre));    for(int i=0; i<=ed; i++)    {        dist[i]=inf;        vis[i]=0;        pre[i]=-1;    }    dist[st]=0;    vis[st]=1;    q.push(st);    while(!q.empty())    {        int u=q.front();        q.pop();        vis[u]=0;        for(int i=head[u]; i!=-1; i=node[i].next)        {            int v=node[i].v;            if(node[i].w&&dist[v]>dist[u]+node[i].cost)            {                dist[v]=dist[u]+node[i].cost;                pre[v]=i;                if(!vis[v])                {                    vis[v]=1;                    q.push(v);                }            }        }    }    if(dist[ed]==inf) return 0;//找不到最短路    return 1;}int MCMF(int st,int ed){    int mincost=0,flow=0;    while(SPFA(st,ed))//有最短路 更新残留网络    {        int mins=inf;        for(int i=pre[ed]; i!=-1; i=pre[node[i].u])//找到这条路径上的最小能更新的流量            mins=min(mins,node[i].w);        for(int i=pre[ed]; i!=-1; i=pre[node[i].u])//更新流量        {            node[i].w-=mins;            node[i^1].w+=mins;        }        mincost+=dist[ed]*mins;//每次找到最短路后更新最小费用        flow+=mins;//更新最大流    }    sumflow=flow;//最大流    return mincost;}int main(){    int ncase;    scanf("%d",&ncase);    while(ncase--)    {        init();        int n,m;        scanf("%d%d",&n,&m);        int st=0,ed=2*n+1;        for(int i=1; i<=n; i++)        {            add(st,i,1,0);            add(i+n,ed,1,0);        }        for(int i=0; i<m; i++)        {            int a,b,c;            scanf("%d%d%d",&a,&b,&c);            add(a,b+n,1,c);        }        int ans=MCMF(st,ed);//最小费用最大流        printf("%d\n",ans);    }    return 0;}

题目链接请点这里
双向图

#include<cstdio>//每次找费用的最短路,更新残留网络图直到找不到最短路为止#include<cstring>//最大费用  权值取负值  结果取负值#include<iostream>#include<algorithm>#include<queue>using namespace std;const int inf=0x3f3f3f3f;struct Node{    int u,v,w,cost,next;}node[1001000];int head[1001000],cont,sumflow;int vis[101000],dist[101000];int pre[101000];void init(){    cont=0;    sumflow=0;    memset(head,-1,sizeof(head));}void add(int u,int v,int w,int cost)//建图{    int i;    for(i=head[u]; i!=-1; i=node[i].next)//去重边    {        if(node[i].v==v)        {            if(node[i].cost>cost)//更新重边的费用,有时是双向边            {                //cost,-cost;//第二条边                node[i^2].cost=node[i].cost=cost,node[(i^1)^2].cost=node[i^1].cost=-cost;//第一条边            }            return ;        }    }    node[cont].u=u,node[cont].v=v;    node[cont].w=w,node[cont].cost=cost;    node[cont].next=head[u],head[u]=cont++;    node[cont].u=v,node[cont].v=u;    node[cont].w=0,node[cont].cost=-cost;//反向边费用为负的    node[cont].next=head[v],head[v]=cont++;}int SPFA(int st,int ed)//寻找最短路{    queue<int> q;    //memset(vis,0,sizeof(vis));//数组太大容易超时    //memset(pre,-1,sizeof(pre));    for(int i=0; i<=ed; i++)    {        dist[i]=inf;        vis[i]=0;        pre[i]=-1;    }    dist[st]=0;    vis[st]=1;    q.push(st);    while(!q.empty())    {        int u=q.front();        q.pop();        vis[u]=0;        for(int i=head[u]; i!=-1; i=node[i].next)        {            int v=node[i].v;            if(node[i].w&&dist[v]>dist[u]+node[i].cost)            {                dist[v]=dist[u]+node[i].cost;                pre[v]=i;                if(!vis[v])                {                    vis[v]=1;                    q.push(v);                }            }        }    }    if(dist[ed]==inf) return 0;//找不到最短路    return 1;}int MCMF(int st,int ed){    int mincost=0,flow=0;    while(SPFA(st,ed))//有最短路 更新残留网络    {        int mins=inf;        for(int i=pre[ed]; i!=-1; i=pre[node[i].u])//找到这条路径上的最小能更新的流量            mins=min(mins,node[i].w);        for(int i=pre[ed]; i!=-1; i=pre[node[i].u])//更新流量        {            node[i].w-=mins;            node[i^1].w+=mins;        }        mincost+=dist[ed]*mins;//每次找到最短路后更新最小费用        flow+=mins;//更新最大流    }    sumflow=flow;//最大流    return mincost;}int main(){    int ncase,Z=0;    scanf("%d",&ncase);    while(ncase--)    {        init();        int n,m;        scanf("%d%d",&n,&m);        int st=0,ed=2*n+1;        for(int i=1; i<=n; i++)        {            add(st,i,1,0);            add(i+n,ed,1,0);        }        for(int i=0; i<m; i++)        {            int a,b,c;            scanf("%d%d%d",&a,&b,&c);//双向边            add(a,b+n,1,c);            add(b,a+n,1,c);        }        int ans=MCMF(st,ed);//最小费用最大流        printf("Case %d: ",++Z);        if(sumflow!=n)        printf("NO\n");        else        printf("%d\n",ans);    }    return 0;}

题目链接

0 0
原创粉丝点击