费用流mcmf模板2.0版

题目地址:HDU 3488

今晚才发现以前的费用流模板居然是错的。。。。。。。有漏洞。。。。但是居然都AC了那么多题。。想想也是。。做的费用流也不多,而且都是流量为1的,这个漏洞是不会影响的。因为以前在每次最小费用增广后找到的最小流量是经过的所有路的最小流量,不一定是可以到达汇点的最小流量。。但是如果流量都为1的话。。那只要边没有全部流过,那肯定最小流量会是1.而如果已经全部流过的话。。那也没意义了。。已经到达了最大流了。所以说这个漏洞一直都没被发现。。。

那么应该如何改进呢。那就是跟最短路的方法一样,在标记一个费用数组,随着路径的变化而变化。这样的话,最终的

f[sink]就一定是到达汇点的最小流量。其他地方都是正确的。改了这个地方就OK了。

为了避免前面的代码祸害人间。。。还是找个时间全改过来吧。。TUT

模板如下;

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <queue>
#include <map>
#include <algorithm>

using namespace std;
const int INF=0x3f3f3f3f;
int head[500], source, sink, cnt, flow, cost;
int d[500], pre[500], q[1000000], cur[500], vis[500], f[500];
struct node
{
    int u, v, cap, cost, next;
}edge[1000000];
void add(int u, int v, int cap, int cost)
{
    edge[cnt].v=v;
    edge[cnt].cap=cap;
    edge[cnt].cost=cost;
    edge[cnt].next=head[u];
    head[u]=cnt++;

    edge[cnt].v=u;
    edge[cnt].cap=0;
    edge[cnt].cost=-cost;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}
int spfa()
{
    memset(d,INF,sizeof(d));
    memset(vis,0,sizeof(vis));
    int minflow=INF, f1=0, f2=0, i;
    q[f1++]=source;
    f[source]=INF;
    d[source]=0;
    cur[source]=-1;
    while(f1>=f2)
    {
        int u=q[f2++];
        vis[u]=0;
        for(i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].v;
            if(d[v]>d[u]+edge[i].cost&&edge[i].cap)
            {
                d[v]=d[u]+edge[i].cost;
                f[v]=min(f[u],edge[i].cap);
                cur[v]=i;
                if(!vis[v])
                {
                    q[f1++]=v;
                    vis[v]=1;
                }
            }
        }
    }
    if(d[sink]==INF) return 0;
    flow+=f[sink];
    cost+=f[sink]*d[sink];
    for(i=cur[sink];i!=-1;i=cur[edge[i^1].v])
    {
        edge[i].cap-=f[sink];
        edge[i^1].cap+=f[sink];
    }
    return 1;
}
void mcmf()
{
    flow=cost=0;
    while(spfa()) ;
    printf("%d\n",cost);
}
int main()
{
    int T, n, m, i, j, a, b, c;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        memset(head,-1,sizeof(head));
        cnt=0;
        source=0;
        sink=2*n+1;
        flow=0;
        cost=0;
        for(i=1;i<=n;i++)
        {
            add(source,i,1,0);
            add(i+n,sink,1,0);
        }
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a,b+n,1,c);
        }
        mcmf();
    }
    return 0;
}

费用流mcmf模板2.0版

时间: 2024-10-10 21:53:10

费用流mcmf模板2.0版的相关文章

POJ 2195 - Going Home - [最小费用最大流][MCMF模板]

题目链接:http://poj.org/problem?id=2195 Time Limit: 1000MS Memory Limit: 65536K Description On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertically, to an adjacent

洛谷P3381——费用流模板题

嗯..随便刷了一道费用流的模板题....来练练手. #include<iostream> #include<cstdio> #include<cstring> using namespace std; int h[5210],d[5210],used[5210],que[100010],last[5210]; int k=1,INF=0x7fffffff,ans1=0,ans2=0; inline int read(){ int t=1,num=0; char c=ge

CF 277E Binary Tree on Plane (拆点 + 费用流) (KM也可做)

题目大意: 平面上有n个点,两两不同.现在给出二叉树的定义,要求树边一定是从上指向下,即从y坐标大的点指向小的点,并且每个结点至多有两个儿子.现在让你求给出的这些点是否能构成一棵二叉树,如果能,使二叉树的树边长度(欧几里德长度)总和最小,输出这个总和.如果不能,输出-1.答案与标准答案相差1e-6内都认为是正确的. 算法讨论: 起初是这样想的,肯定是MCMF,费用是距离,然后流量一开始我是这样搞的:从父亲向儿子连流量为2的边.但是你会发现这样有一个问题,就是如果某个结点如果真的有两个儿子的话,那

【bzoj4514】: [Sdoi2016]数字配对 图论-费用流

[bzoj4514]: [Sdoi2016]数字配对 好像正常的做法是建二分图? 我的是拆点然后 S->i cap=b[i] cost=0 i'->T cap=b[i] cost=0 然后能匹配的两点i,j 连 i->j' cap=inf cost=c[i]*c[j] 跑最大费用流,直到 cost<0 或 全部增广完 最后flow/2就是答案 1 /* http://www.cnblogs.com/karl07/ */ 2 #include <cstdlib> 3 #i

【bzoj4930】棋盘 费用流

题目描述 给定一个n×n的棋盘,棋盘上每个位置要么为空要么为障碍.定义棋盘上两个位置(x,y),(u,v)能互相攻击当前仅 当满足以下两个条件: 1:x=u或y=v 2:对于(x,y)与(u,v)之间的所有位置,均不是障碍. 现在有q个询问,每个询问给定ki,要求从棋盘中选出ki个空位置来放棋子,问最少互相能攻击到的棋子对数是多少? 输入 第一行一个整数n. 接下来输入一个n×n的字符矩阵,一个位置若为.,则表示这是一个空位置,若为#,则为障碍. 第n+2行输入一个整数q代表询问个数. 接下来q

图论模板——最大流及费用流模板

图论模板--最大流及费用流模板 最大流--SAP 时间复杂度:O(v^2*e) const int MAXN=1010;//点数的最大值 const int MAXM=1010;//边数的最大值 const int INF=0x3f3f3f3f; struct Node { int from,to,next; int cap; }edge[MAXM]; int tol; int head[MAXN]; int dep[MAXN]; int gap[MAXN];//gap[x]=y :说明残留网络

费用流模板(带权二分图匹配)——hdu1533

/* 带权二分图匹配 用费用流求,增加源点s 和 汇点t */ #include<bits/stdc++.h> using namespace std; #define maxn 10005 #define maxm 200005 struct Edge{int to,nxt,w,c;}e[maxm<<1]; int head[maxn],tot,n,m,s,t,ans,maxflow; char mp[maxn][maxn]; vector<pair<int,int&

网络流之费用流问题

费用流即最小费用最大流 先贴上粉书上的模板: struct Edge { int from,to,cap,flow,cost; Edge(int u,int v,int c,int f,int w): from(u),to(v),cap(c),flow(f),cost(w) {} }; int n,m; vector<Edge> edges; vector<int> G[maxn]; int inq[maxn]; int d[maxn]; int p[maxn]; int a[ma

HDU 6118 2017百度之星初赛B 度度熊的交易计划(费用流)

度度熊的交易计划 Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 254    Accepted Submission(s): 80 Problem Description 度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题: 喵哈哈村以及周围的村庄可以看做是一共由n个片区,m条公路组成的地区. 由于生产能力的区别,第i个片