POJ 2516Minimum Cost(最小费用流+特判)

题意】:

有N个人,M个仓库,每个人需要物品,个数都等于共同的K,仓库中有对应的K件物品的数量,随后给K个N*M矩阵(小写k, n, m表示K,N,M对应的子集),表明m个仓库到第n个人的位置运送k物品的花费,求

满足所有人的订单要求所需要的花费,如果不能满足所有人则输出-1

思路】:

我的思路是建立源点sp,汇点tp, 把仓库和人所在的点都进行拆分,对每个仓库拆分成K个点,可以想象成一个大仓库由K个小仓库组成,每个小仓库只发放第k种物品,每个人也分成K个点,每个点接受一种k物品,sp与仓库的拆点进行连边,权重为这个小仓库存放的k物品的数量,花费为0,人的拆点与tp连边,权重为人拆点所需要的k物品的数量,费用为0,最后将仓库的拆点人的拆点进行连边,权重为inf,费用为矩阵中对应的费用。

重要】——>解决TLE问题

我的想法可能与网上的题解不同,我看有很多是分别跑k次费用流,最后的费用总和为结果,我在一开始也是疯狂TLE,然后加上特判就过了?

特判】——>解决TLE

将输入分成三部分与N有关——与M有关——K个N*M矩阵

判定是否有供不应求的情况,将前两部分输入(N*K和N*K)分别存储下来,N*K代表所需要的部分,M*K代表供应的部分,对每个k进行遍历,然后求每个n的和sum1,每个m的和sum2,如果sum1>sum2则不对第三部分输入处理(K个N*M矩阵),待输入结束后不进行费用流算法,直接输出-1即可

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;

const int maxn = 1e4 + 5;
const int maxe = 1e6 + 5;
const int N = 100 + 5;
const int inf = 0x3f3f3f3f;
struct edge{
    int to, w, c, next;
} ed[maxe];
int head[maxn], tot, ns;
int n, m, k, ware[N][N], p[N][N];
int sp, tp, d[maxn], pre[maxn], a[maxn];
bool inq[maxn];
inline void init(){
    memset( head, -1, sizeof(head) ) ;
    tot = 1;
    ns = (n+m)*k+2;
    sp = 0; tp = ns-1;
}

inline void add( int u, int v, int w, int c ){
    ed[++tot].to = v; ed[tot].w = w; ed[tot].c = c; ed[tot].next = head[u]; head[u] = tot;
    ed[++tot].to = u; ed[tot].w = 0; ed[tot].c = -c; ed[tot].next = head[v]; head[v] = tot;
}

inline bool spfa( int &flow, int &cost ){
    for( int i=0; i<ns; i++ ){
        inq[i] = 0;
        d[i] = inf;
    }
    queue<int> q;
    d[sp] = pre[sp] = 0;
    a[sp] = inf;
    inq[sp] = 1;
    q.push(sp);
    while( q.size() ){
        int x = q.front();
        q.pop();
        inq[x] = 0;
        for( int i=head[x]; ~i; i=ed[i].next ){
            int y = ed[i].to;
            if( ed[i].w>0 && d[y]>d[x]+ed[i].c ){
                d[y] = d[x]+ed[i].c;
                pre[y] = i;
                a[y] = min(a[x], ed[i].w);
                if( !inq[y] ){
                    inq[y] = 1;
                    q.push(y);
                }
            }
        }
    }
    if( d[tp]==inf ) return 0;
    flow += a[tp];
    cost += a[tp]*d[tp];
    for( int x=tp; x!=sp; x=ed[pre[x]^1].to ){
        ed[pre[x]].w -= a[tp];
        ed[pre[x]^1].w += a[tp];
    }
    return 1;
}

inline void mcmf( int &flow, int &cost ){ while(spfa(flow, cost)); }

int main(){
    while( ~scanf("%d%d%d", &n, &m, &k), (n||m||k) ){
        init();
        int num, sum = 0;
        for( int i=1; i<=n; i++ )
            for( int j=1; j<=k; j++ ){
                scanf("%d", &p[i][j]);
                sum += p[i][j];
                add( (i-1)*k+j, tp, p[i][j], 0 );
            }
        for( int i=1; i<=m; i++ )
            for( int j=1; j<=k; j++ ){
                scanf("%d", &ware[i][j]);
                add( sp, (i-1)*k+j+n*k, ware[i][j], 0 );
            }
        bool flag = 0;                  
        for( int i=1; i<=k; i++ ){
            int sum1 = 0, sum2 = 0;
            for( int j=1; j<=n; j++ ) sum1 += p[j][i];
            for( int j=1; j<=m; j++ ) sum2 += ware[j][i];
            if( sum2<sum1 ) {flag = 1; break;}              //判断是否存在供不应求,如果存在则直接输出-1
        }
        for( int l=1; l<=k; l++ )
            for( int i=1; i<=n; i++ )
                for( int j=1; j<=m; j++ ){
                    int num;
                    scanf("%d", &num);
                    if( flag ) continue;                    //如果出现供不应求则不进行处理,只读取数据即可
                    add( (j-1)*k+l+n*k, (i-1)*k+l, inf, num );
                }
        if( flag ){ puts("-1"); continue; }             //输出-1
        int flow = 0, cost = 0;
        mcmf(flow, cost);
        if( flow>=sum ) printf("%d\n", cost);
        else puts("-1");
    }
    
    return 0;
}

 

posted @ 2019-10-14 14:54  CoffeeCati  阅读(127)  评论(0编辑  收藏  举报