[POJ 2516]Minimum Cost[费用流][建图]

来源:互联网 发布:sql注入语句 编辑:程序博客网 时间:2024/04/28 19:05
题目链接:[POJ 2516]Minimum Cost[费用流][建图]

题意分析:

N个店主,M个供货商,K种货物,每个店主都有自己需要的货物数量,每个供货商都会提供一定数量的货物,每个供货商给店主提供不同货物的单位价格不同,现在问题来了:供货商如何花费最少的费用给店主提供上货物呢?最少费用是多少?无法满足要求则输出-1。

解题思路:

这题如果将店主的需要货物拆点,供货商的提供货物拆点,再来个超级源汇点,边的个数多的吓人。。。。。

发现可以一种货物计算一次费用,返回的最大流就是这种货物能够提供的最大总数,如果这个最大流<店主需要的量,那么就是-1了。

于是我们一种货物建一次图,源点到供货商连一条边,容量为供货量,费用为0,汇点和店主连一条边,容量为需求量,费用为0,供货商和店主连边,容量为INF,费用为当前矩阵对应的费用。此题得解。

个人感受:

个人思路一直是第一行的解题思路。。。。。各种拆点。。。。。这回知道连图都能拆了。。。。

具体代码如下:

#include<algorithm>#include<cctype>#include<cmath>#include<cstdio>#include<cstring>#include<iomanip>#include<iostream>#include<map>#include<queue>#include<set>#include<sstream>#include<stack>#include<string>#define ll long long#define pr(x) cout << #x << " = " << (x) << '\n';using namespace std;const int MAXN = 200;const int MAXM = 2e4;const int INF = 0x3f3f3f3f;struct Edge{    int to,next,cap,flow,cost;}edge[MAXM];int head[MAXN], tol, nk[60][60], mk[60][60], need[60], have[60];int pre[MAXN],dis[MAXN];bool vis[MAXN];int N;//节点总个数,节点编号从0~N-1void init(int n){    N = n;    tol = 0;    memset(need, 0, sizeof need);    memset(have, 0, sizeof have);}void addedge(int u,int v,int cap,int cost){    edge[tol].to = v;    edge[tol].cap = cap;    edge[tol].cost = cost;    edge[tol].flow = 0;    edge[tol].next = head[u];    head[u] = tol++;    edge[tol].to = u;    edge[tol].cap = 0;    edge[tol].cost = -cost;    edge[tol].flow = 0;    edge[tol].next = head[v];    head[v] = tol++;}bool spfa(int s,int t){    queue<int>q;    for(int i = 0;i < N;i++)    {        dis[i] = INF;        vis[i] = false;        pre[i] = -1;    }    dis[s] = 0;    vis[s] = true;    q.push(s);    while(!q.empty())    {        int u = q.front();        q.pop();        vis[u] = false;        for(int i = head[u]; i != -1;i = edge[i].next)        {            int v = edge[i].to;            if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost )            {                dis[v] = dis[u] + edge[i].cost;                pre[v] = i;                if(!vis[v])                {                    vis[v] = true;                    q.push(v);                }            }        }    }    if(pre[t] == -1)return false;    else return true;}//返回的是最大流, cost存的是最小费用int minCostMaxflow(int s,int t,int &cost){    int flow = 0;    while(spfa(s,t))    {        int Min = INF;        for(int i = pre[t];i != -1;i = pre[edge[i^1].to])        {            if(Min > edge[i].cap - edge[i].flow)            Min = edge[i].cap - edge[i].flow;        }        for(int i = pre[t];i != -1;i = pre[edge[i^1].to])        {            edge[i].flow += Min;            edge[i^1].flow -= Min;            cost += edge[i].cost * Min;        }        flow += Min;    }    return flow;}int main(){    int n, m, k;    while (~scanf("%d%d%d", &n, &m, &k) && (n|m|k)) {        init(n + m + 2);        int s = 0, t = n + m + 1;        for (int i = 1; i <= n; ++i) {            for (int j = 1; j <= k; ++j)                scanf("%d", &nk[i][j]), need[j] += nk[i][j];        }        for (int i = 1; i <= m; ++i) {            for (int j = 1; j <= k; ++j)                scanf("%d", &mk[i][j]), have[j] += mk[i][j];        }        bool flag = 0;        int x = 0, ans = 0;        for (int l = 1; l <= k; ++l) {            tol = 0;            memset(head, -1, sizeof head);            for (int i = 1; i <= n; ++i) {                for (int j = 1; j <= m; ++j) {                    scanf("%d", &x);                    addedge(n + j, i, mk[j][l], x);                }            }            for (int i = 1; i <= n; ++i) addedge(i, t, nk[i][l], 0);            for (int i = 1; i <= m; ++i) addedge(s, i + n, mk[i][l], 0);            int flow = minCostMaxflow(s, t, ans);            if (flow < need[l]) flag = 1;        }        if (flag) printf("-1\n");        else printf("%d\n", ans);    }    return 0;}


0 0