最小花费最大流模板csu 1506

//#if 0
#include <map>
#include <queue>
#include <math.h>
#include <string>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <queue>
#include <vector>
#include <set>
using namespace std;
#define ull unsigned long long
#define ll long long
#define cls(x) memset(x,0,sizeof(x))
#define clslow(x) memset(x,-1,sizeof(x))
const int maxn=1e5+10;
const int INF=0x3f3f3f3f;

int head[10000],cnt,n,m,dis[10000],vis[10000],pre[10000];

struct edg
{
    int di,ai,v,nex,f,c,u;
    edg(){}
    edg(int di,int ai,int v,int nex,int f,int c):di(di),ai(ai),v(v),nex(nex),
    f(f),c(c){}
}l[10000];

void addline(int u,int v,int di,int ai,int f,int c)//链式前向星存图
{
    l[cnt].di=di;
    l[cnt].ai=ai;
    l[cnt].v=v;
    l[cnt].u=u;
    l[cnt].c=c;
    l[cnt].f=f;
    l[cnt].nex=head[u];
    head[u]=cnt++;

    l[cnt].di=-di;//反向边一起存了,花费是负数,起点终点交换,容量设置为1,流量为0
    l[cnt].ai=ai;
    l[cnt].u=v;
    l[cnt].v=u;
    l[cnt].f=0;
    l[cnt].c=0;
    l[cnt].nex=head[v];
    head[v]=cnt++;
}

int spfa(int s,int t)//稍微增加一点判断的spfa
{
    memset(dis,INF,sizeof(dis));
    memset(pre,-1,sizeof(pre));
    memset(vis,0,sizeof(vis));
    queue<int>q;
    dis[s]=0;
    vis[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for( int i=head[u] ; i!=-1 ; i=l[i].nex ){
            if(l[i].c > l[i].f && l[i].di+dis[l[i].u] < dis[l[i].v])
            {//判断容量大于当前流量,并且是可以松弛的边,才进行松弛;
            //用于防止未被加入网络的边先行被选为最短路;
                dis[l[i].v]=l[i].di+dis[l[i].u];
                pre[l[i].v]=i;//用于找最短路路径的数组,pre【i】存放的就是到达i
                //点,上一条经过的是第i条路,这个i针对的是存放线段的数组l,即l[i];
                if(vis[l[i].v]==0){
                    q.push(l[i].v);
                    vis[l[i].v]=1;
                }
            }
        }
    }
//    for(int i=0;i<=n+1;i++){
//        cout<<dis[i]<<" ";
//    }cout<<endl;
    if(dis[t]==INF)return 0;//当各个重要通道流量满了,找不到通往汇点的路,返回0
    else return 1;//从而使下方的循环退出
}

//void ou()
//{
//    cout<<"---------------------------"<<endl;
//    for(int i=0;i<cnt;i++){
//        cout<<l[i].di<<" "<<l[i].f<<endl;
//    }
//}

int min_cost(int s,int t,int &cost)
{
    int f=0;//最大流量先设置为0
    cost=0;//最小花费也先设置为0
    while(spfa(s,t))
    {
        int Min=INF;//这个Min用来找刚才最短路上(容量-流量)的最小值,这样
        //刚才找到的最短路,每条路都加上这个最小值,也不可能超过每条路的容量;
        for(int i=pre[t];i!=-1;i=pre[l[i].u])
        {//前向星式的查找路径;
//            cout<<l[i].u<<" "<<l[i].v<<" "<<l[i].c<<" "<<l[i].f<<endl;
            Min=min(l[i].c-l[i].f,Min);
        }
        for(int i=pre[t];i!=-1;i=pre[l[i].u])
        {
            l[i].f+=Min;//路径被走过,则正向的流量加上Min
            l[i^1].f-=Min;//反向的流量减少Min,因为反向的流量和容量都是0,减少
          //后流量就是负数了,相当于加入的网络,下次spfa操作,其可能会被选为最短路
          //因为加边操作的时候,正向反向边都是一起加的,所以i^1就是反向边;
          //^异或操作太骚了,存边的时候是01,23,34。。。。一对一对,4^1就是3
          //3^1就是4了
            cost+=l[i].di;
        }
        f+=Min;
    }
    return f;
}

int main()
{
//    freopen("in1.txt", "r", stdin);
//    freopen("out1.txt", "w", stdout);
    int cas=1;
    while(~scanf("%d%d",&n,&m))
    {
        memset(head,-1,sizeof(head));
        cnt=0;
        int u,v,di,ai;
        while(m--){
            scanf("%d%d%d%d",&u,&v,&di,&ai);
            addline(u,v,di,ai,0,1);
            addline(u,v,di+ai,ai,0,1);
        }
        int ans=0;
        addline(0,1,0,0,0,2);//建立源点
        addline(n,n+1,0,0,0,2);//建立汇点
        min_cost(0,n+1,ans);
        printf("Case %d: %d\n",cas++,ans);
    }
    return 0;
}

//#endif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值