首页 > 代码库 > wikioi 1028 最大费用最大流

wikioi 1028 最大费用最大流

思路:这题刚开始一看没太懂,然后想想原来是裸的最大费用最大流,建图后搞下就行了。

不过题目说是用二分匹配来做,因为自己二分匹配的那个带权匹配不会,所以直接用最小费用最大流来做了,反正都一样能求。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<bitset>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define llson j<<1,l,mid
#define rrson j<<1|1,mid+1,r
#define INF 0x7fffffff
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
#define maxn 20005
struct
{
    int v,w,c,next,re;
    //re记录逆边的下标,c是费用,w是流量
} e[maxn];
int sink,cnt,flow,minflow;
int head[maxn],que[maxn*10],pre[maxn],dis[maxn];
bool vis[maxn];
void add(int u, int v, int w, int c)
{
    e[cnt].v=v,e[cnt].w=w,e[cnt].c=c;
    e[cnt].next=head[u];
    e[cnt].re=cnt+1,head[u]=cnt++;
    e[cnt].v=u,e[cnt].w=0,e[cnt].c=-c;
    e[cnt].next=head[v];
    e[cnt].re=cnt-1,head[v]=cnt++;
}
bool spfa()
{
    int i, l = 0, r = 1;
    for(i = 0; i <= sink; i ++)
        dis[i] = INF,vis[i] = false;
    dis[0]=0,que[0]=0,minflow=INF,vis[0]=true;
    while(l<r)
    {
        int u=que[l++];
        for(i=head[u]; i!=-1; i=e[i].next)
        {
            int v = e[i].v;
            if(e[i].w&&dis[v]>dis[u]+e[i].c)
            {
                dis[v] = dis[u] + e[i].c;
                minflow=min(minflow,e[i].w);
                pre[v] = i;
                if(!vis[v])
                {
                    vis[v] = true;
                    que[r++] = v;
                }
            }
        }
        vis[u] = false;
    }
    return dis[sink]!=INF;
}
int change()
{
    int i,p;
    for(i=sink; i!=0; i=e[e[p].re].v)
    {
        p=pre[i];
        e[p].w-=minflow;
        e[e[p].re].w+=minflow;
    }
    flow+=minflow;
    return minflow*dis[sink];
}
int EK()
{
    int sum=0;
    while(spfa()) sum+=change();
    return sum;
}
void init()
{
    mem(head,-1),mem(pre,0),cnt=0,flow=0;
}
int main()
{
    int n,m,i,j,a;
    scanf("%d%d",&n,&m);
    init();
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
        {
            scanf("%d",&a);
            add(i,n+j,1,-a);
        }
    sink=n+m+1;
    for(i=1;i<=n;i++)
        add(0,i,1,0);
    for(i=1;i<=m;i++)
        add(n+i,sink,1,0);
    printf("%d\n",-EK());
    return 0;
}


wikioi 1028 最大费用最大流