POJ 2516 跑k次的最小费用最大流

题目大意:给出n个客户对k个商品的需求量,又给出m个仓库对k个物品的存货量以及对k个物品从i仓库到j客户的一个物品的运费价格,让判断是否可以满足客户需求,然后就是如果满足求出最小的运费,是典型的最小费用最大流!

思路:可以将k中物品分开求最小费用最大流,然后想加得到总的最小费用最大流!

建图,对每个仓库是一个结点,每个客户也是一个结点,除此之外再加上s源点和t结束点!

1、s到仓库i的边的流量为仓库i的供给量,费用没有当然为0;

2、仓库i到客户j的流量为仓库的供给量,费用为仓库i到客户j的运输费用;

3、客户j到t的流量为客户的需求量,费用没有当然也为0;

#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 n,cnt;
int head[maxn],que[maxn*8],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 <= n; i ++)
        dis[i] = INF,vis[i] = false;
    dis[0]=0,que[0]=0,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;
                pre[v] = i;
                if(!vis[v])
                {
                    vis[v] = true;
                    que[r++] = v;
                }
            }
        }
        vis[u] = false;
    }
    return dis[n]!=INF;
}
int change()
{
    int i,p,sum=INF,ans=0;
    for(i=n;i!=0;i=e[e[p].re].v)
    {//e[e[p].re].v为前向结点,不理解看add和spfa
        p=pre[i];//p为前向结点编号
        sum=min(sum,e[p].w);
    }
    for(i=n;i!=0;i=e[e[p].re].v)
    {
        p=pre[i];
        e[p].w-=sum;
        e[e[p].re].w+=sum;
        ans+=sum*e[p].c;//c记录的为单位流量费用,必须得乘以流量。
    }
    return ans;
}
int EK()
{
    int sum=0;
    while(spfa()) sum+=change();
    return sum;
}
void init()
{
    mem(head,-1),mem(pre,0),cnt=0;
}
int a[51][51],b[51][51],cost[51][101],aa[51],bb[51];
int main()
{
    //freopen("1.txt","r",stdin);
    int N,m,K;
    while(~scanf("%d%d%d",&N,&m,&K))
    {
        if(!N&&!m&&!K) break;
        int i,j,k,flag=0,sum=0,s=0,t=m+N+1;
        mem(aa,0),mem(bb,0);
        for(i=1;i<=N;i++)
            for(j=1;j<=K;j++)
            {
                scanf("%d",&a[i][j]);
                aa[j]+=a[i][j];
            }
        for(i=1;i<=m;i++)
            for(j=1;j<=K;j++)
            {
                scanf("%d",&b[i][j]);
                bb[j]+=b[i][j];
            }
        for(i=1;i<=K;i++)
            if(bb[i]<aa[i]) {flag=1;break;}
        for(k=1;k<=K;k++)
        {
            for(i=m+1;i<=N+m;i++)
                for(j=1;j<=m;j++)
                    scanf("%d",&cost[j][i]);
            if(flag) continue;
            init();
            for(i=1;i<=m;i++)
                add(s,i,b[i][k],0);
            for(i=1;i<=m;i++)
                for(j=m+1;j<=N+m;j++)
                    add(i,j,b[i][k],cost[i][j]);
            for(i=m+1;i<=m+N;i++)
                add(i,t,a[i-m][k],0);
            n=t;
            sum+=EK();//每种k物品都求一次
        }
        if(flag) puts("-1");
        else printf("%d\n",sum);
    }
    return 0;
}
时间: 2024-10-10 17:52:30

POJ 2516 跑k次的最小费用最大流的相关文章

poj3680 Intervals 区间k覆盖问题 最小费用最大流 建图巧妙

/** 题目:poj3680 Intervals 区间k覆盖问题 最小费用最大流 建图巧妙 链接:http://poj.org/problem?id=3680 题意:给定n个区间,每个区间(ai,bi),以及权值wi.选出一些区间,满足权值和最大且任何一个点不会被超过k个区间覆盖. 思路: 建图:对于每个区间(ai,bi). ai->bi,cap = 1,cost = -wi; (离散化后的ai,bi) 所有区间的端点放到数组,进行从小到大排序,去重,离散化,在数组内相邻的u端点,v端点.u->

POJ 3422Kaka&#39;s Matrix Travels(最小费用最大流)

Kaka's Matrix Travels Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9460   Accepted: 3844 Description On an N × N chessboard with a non-negative number in each grid, Kaka starts his matrix travels with SUM = 0. For each travel, Kaka mo

POJ 2195:Going Home(最小费用最大流)

http://poj.org/problem?id=2195 题意:有一个地图里面有N个人和N个家,每走一格的花费是1,问让这N个人分别到这N个家的最小花费是多少. 思路:通过这个题目学了最小费用最大流.最小费用最大流是保证在流量最大的情况下,使得费用最小. 建图是把S->人->家->T这些边弄上形成一个网络,边的容量是1(因为一个人只能和一个家匹配),边的费用是曼哈顿距离,反向边的费用是-cost. 算法的思想大概是通过SPFA找增广路径,并且找的时候费用是可以松弛的.当找到这样一条增

POJ 2195 &amp; HDU 1533 Going Home(最小费用最大流)

题目链接: POJ:http://poj.org/problem?id=2195 HDU:http://acm.hdu.edu.cn/showproblem.php?pid=1533 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,

poj 2135 Farm Tour 【无向图最小费用最大流】

题目:poj 2135 Farm Tour 题意:给出一个无向图,问从 1 点到 n 点然后又回到一点总共的最短路. 分析:这个题目不读仔细的话可能会当做最短路来做,最短路求出来的不一定是最优的,他是两条分别最短,但不一定是和最短. 我们可以用费用流来很轻易的解决,建边容量为1,费用为边权,然后源点s连 1 ,费用0 ,容量 2 ,n点连接汇点,容量2,费用0,,就可以了. 注意这个题目是无向图,所以要建双向边. AC代码: #include <iostream> #include <a

poj 2526 Minimum Cost【最小费用最大流】

题目链接:http://poj.org/problem?id=2516 题意: n个店主 m个供应商 k种货物 给你店主对k种货物的需求及供货商k种货物的囤货量及K种运输费用. 解法:k次费用流,分别求每种货物的费用.源点到供应点建边,店主到汇点建边,费用均为0,容量为1.然后供应点到店主建边,费用为矩阵,容量无穷大即可. 代码: /* POJ 2195 Going Home 邻接矩阵形式最小费用最大流 */ #include<stdio.h> #include<iostream>

poj 2195 最小费用最大流模板

/*Source Code Problem: 2195 User: HEU_daoguang Memory: 1172K Time: 94MS Language: G++ Result: Accepted Source Code */ #include <iostream> #include <stdio.h> #include <queue> #include <math.h> #include <string.h> using namespa

POJ 2516 Minimum Cost(最小费用最大流啊)

题目链接:http://poj.org/problem?id=2516 Description Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his sale area there are N shopkeepers (marked from 1 to N) which stocks goods from him.Dearboy has M supply places (mar

POJ 2516 Minimum Cost (最小费用最大流)

POJ 2516 Minimum Cost 链接:http://poj.org/problem?id=2516 题意:有M个仓库,N个商人,K种物品.先输入N,M,K.然后输入N行K个数,每一行代表一个商人要购买的物品,其中K个数分别表示要购买的每件商品数.然后是M行K个数,每行表示仓库里的情况,其中K个数分别每种物品的库存量.接下来是K个矩阵,每个矩阵为N*M,分别表示第K种物品从M个仓库运到第N个商人的花费.问能否合理安排,使得花费最少,如果不行就输出-1. 思路: 一开始的时候,竟然构造了