POJ 2516(最小费用最大流, 多次建图)

题目链接: http://poj.org/problem?id=2516

说一下输入:  第一行是三个整数, n,m,k,分别代表n个商户,m个仓库,k种物品。 接着是n 行,每行k个整数, 意思是 在这 n 行中 , 第 i 行 第 j 列 就表示 第 i 个商户对 第 j 种物品的需求量。 然后是m 行,在这m 行中, 第 i 行第 j 列表示 第 j 种物品 放置在 第 i 个仓库的数量。接着是有 k 个矩阵,每个矩阵大小是 n*m, 三者整体就代表 第 K(1 <= K <= k) 种物品 位于 j 地点  运输到 i 商户 需要的费用。

思路: 就是最小费用最大流。 跑k次就可以了, 注意 每一次的最大流 应该和 全部商户对 第K 种物品的需求量相等,否则就是供不应求 输出-1;

关键是有思路,然后建图啊!!!!!!!  看了人家的思路才明白。 呼.... 菜是原罪

AC代码:

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

const int maxsize = 60;
const int maxn = 3000;
const int inf = 0x3f3f3f3f;
int need[maxsize][maxsize];
int locate[maxsize][maxsize];
struct node{
    int u,v,cap,cost;
    node(int u,int v,int cap,int cost):u(u),v(v),cap(cap),cost(cost){}
};
int vis[maxn];
int dis[maxn];
int pre[maxn];
int flow[maxn];
vector<node>edges;
vector<int> G[maxn];

void add(int u,int v,int cap,int cost){
    edges.push_back(node(u,v,cap,cost));
    edges.push_back(node(v,u,0,-cost));
    int s = edges.size();
    G[u].push_back(s - 2);
    G[v].push_back(s - 1);
}

bool spfa(int s,int t,int &c,int &sum){
    memset(vis,0,sizeof(vis));
    memset(dis,inf,sizeof(dis));
    memset(flow,0,sizeof(flow));
    dis[s] = 0; vis[s] = 1;
    flow[s] = inf;
    queue<int> Q;
    Q.push(s);
    while(!Q.empty()){
        int now = Q.front();
        Q.pop(); vis[now] = 0;
        for(int i = 0;i < G[now].size();i ++){
            node &e = edges[G[now][i]];
            if(e.cap > 0 && dis[e.v] > dis[now] + e.cost){
                flow[e.v] = min(flow[now],e.cap);
                dis[e.v] = dis[now] + e.cost;
                pre[e.v] = G[now][i];
                if(!vis[e.v]){
                    vis[e.v] = 1;
                    Q.push(e.v);
                }
            }
        }
    }
    if(dis[t] == inf) return 0;
    c += dis[t] * flow[t];
    sum += flow[t];
    int k = t;
    while(k != s){
        edges[pre[k]].cap -= flow[t];
        edges[pre[k]^1].cap += flow[t];
        k = edges[pre[k]].u;
    }
    return 1;
}

int main()
{
    int n,m,k;
    while(~scanf("%d%d%d",&n,&m,&k)){
        if(!n && !m && !k) break;
        for(int i = 1;i <= n;i ++){         ///第i 个商户对j 的需求
            for(int j = 1;j <= k;j ++){
                scanf("%d",&need[i][j]);
            }
        }
        for(int i = 1;i <= m;i ++){         ///第i个仓库 对j 的储存
            for(int j = 1;j <= k;j ++){
                scanf("%d",&locate[i][j]);
            }
        }
        int flag = 1,ans = 0;
        for(int goods = 1;goods <= k;goods ++){         ///物资k
            int c;
            for(int i = 0;i < maxn;i ++) G[i].clear();
            edges.clear();
            for(int i = 1;i <= n;i ++){
                for(int j = 1;j <= m;j ++){
                    scanf("%d",&c);
                    add(j,m + i,inf,c);
                }
            }
            if(!flag) continue;                     ///有一次 供不应求 后面都不用再算了
            for(int j = 1;j <= m;j ++){
                add(0,j,locate[j][goods],0);
            }
            int sum = 0;
            for(int i = 1;i <= n;i ++){
                add(m + i,m + n + 1,need[i][goods],0);
                sum += need[i][goods];
            }
            int all = 0,co = 0;                         ///co 是每一次的费用, ans 是总费用, all 是每一次的最大流
            while(spfa(0,m + n + 1,co,all));           ///min_cost_maxflow
          //  printf("all : %d\nsum: %d\n",all,sum);
            if(all != sum) flag = 0;
            ans += co;
        }
        if(flag) printf("%d\n",ans);
        else printf("-1\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/no_O_ac/article/details/81358610
今日推荐