网络流 (邻接矩阵)——HDU 2516

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

  • 分析:
    给出N个商店,M个厂家,K种货物,然后给出N个商店对于K种货物的需求量,和M个厂家对于K种货物的供给量,最后给出没种货物的每一份分别从N个商店运输到M个厂家的花费。求能不能满足着N个商店的需求,若能够输出最小花费,若不能,输出-1/。
    一看便是一道网络流的题,辛苦建完边后发现超时了,结果是因为邻接矩阵查询超时的,这里注意一下:

邻接矩阵法由于没有相连的边也占有空间,因此存在浪费空间的问题,而临街链表法合理利用存储空间;

邻接链表法比较耗时,牺牲很大的时间来查找,因此比较耗时,而邻接矩阵法相比邻接链表法来说,时间复杂度低;

总结,邻接矩阵法:用时间换空间;邻接链表法:用空间换时间。
  • 题解:
    1.建边方法:
    邻接矩阵法:从S=0源点到N个店家的K个商品建边,容量为需求量,花费为0;再从N个店家的每K个商品到M个店家的每K个商品建边,容量为供给量,花费为运费;最后从M个店家的每K个商品到汇点T建边,容量为供给量,花费为0;
memset(capacity, 0, sizeof(capacity));
memset(flow, 0, sizeof(flow));
memset(weight, 0, sizeof(weight));
for (j = 1; j <= m; j++) 
{
    capacity[0][j] = capacity_have[j][i]; //S 到N个K
}
for (j = 1; j <= n; j++) 
{
    capacity[m + j][m + n + 1] = capacity_need[j][i];//M个K到T
}
for (j = 1; j <= m; j++) 
{
    for (d = 1; d <= n; d++) 
    {
        capacity[j][d + m] = capacity_have[j][i];//N个K到M个K
    }
}
for (j = 1; j <= m; j++) 
{
    for (d = 1; d <= n; d++) 
    {
        weight[j][d + m] = construction_cost[i][j][d];   //记录N到M的花费
        weight[d + m][j] = -construction_cost[i][j][d];  //反向花费为负数,便于退流
    }
}

2.SPFA(邻接矩阵版本)

int shortestdistances[M];
int pre_node[M];
bool visited[M];
bool spfa() 
{
    for (int i = 0; i <= n + m + 1; i++) 
    {
        shortestdistances[i] = inf;
        pre_node[i] = -1;
        visited[i] = false;
    }
    shortestdistances[0] = 0;
    visited[0] = true;
    queue <int> q;
    q.push(0);
    while (!q.empty()) 
    {
        int t = q.front();
        q.pop();
        visited[t] = false;
        for (int i = 1; i <= n + m + 1; i++) 
        {
            if (capacity[t][i] > flow[t][i] && shortestdistances[i] > shortestdistances[t] + weight[t][i]) 
            {
                shortestdistances[i] = shortestdistances[t] + weight[t][i];
                pre_node[i] = t;
                if (!visited[i]) 
                {
                    q.push(i);
                    visited[i] = true;
                }
            }
        }
    }
    if (pre_node[n + m + 1] == -1) 
    {
        return false;
    }
    return true;
}

3.计算出最校费用

int capacity[M][M];     //邻接矩阵
int flow[M][M];          //流量

void getMaxflow()
{
    while (spfa()) 
    {
        int maxflow = inf;
        int p = n + m + 1;
        while (pre_node[p] != -1) 
        { 
            maxflow = min(maxflow, capacity[pre_node[p]][p] - flow[pre_node[p]][p]); 
            p = pre_node[p];
        }
        p = n + m + 1;
        while (pre_node[p] != -1) 
        {
            flow[pre_node[p]][p] += maxflow;
            flow[p][pre_node[p]] = -flow[pre_node[p]][p];
            p = pre_node[p];
        }
    }
}
  • 参考代码:

#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

#define M 105
#define inf 1 << 30

int capacity_need[M][M];//N个商家的需求
int capacity_have[M][M];//M个厂家的供给
int construction_cost[M][M][M]; //每个物品的具体花费
int n, m, k;
int capacity[M][M];     //邻接矩阵
int flow[M][M];          //流量
int weight[M][M];        //从N到M的花费
int shortestdistances[M];//最短路
int pre_node[M];
bool visited[M];
bool spfa() 
{
    for (int i = 0; i <= n + m + 1; i++) 
    {
        shortestdistances[i] = inf;
        pre_node[i] = -1;
        visited[i] = false;
    }
    shortestdistances[0] = 0;
    visited[0] = true;
    queue <int> q;
    q.push(0);
    while (!q.empty()) 
    {
        int t = q.front();
        q.pop();
        visited[t] = false;
        for (int i = 1; i <= n + m + 1; i++) 
        {
            if (capacity[t][i] > flow[t][i] && shortestdistances[i] > shortestdistances[t] + weight[t][i]) 
            {
                shortestdistances[i] = shortestdistances[t] + weight[t][i];
                pre_node[i] = t;
                if (!visited[i]) 
                {
                    q.push(i);
                    visited[i] = true;
                }
            }
        }
    }
    if (pre_node[n + m + 1] == -1) 
    {
        return false;
    }
    return true;
}

void getMaxflow()
{
    while (spfa()) 
    {
        int maxflow = inf;
        int p = n + m + 1;
        while (pre_node[p] != -1) 
        { 
            maxflow = min(maxflow, capacity[pre_node[p]][p] - flow[pre_node[p]][p]); 
            p = pre_node[p];
        }
        p = n + m + 1;
        while (pre_node[p] != -1) 
        {
            flow[pre_node[p]][p] += maxflow;
            flow[p][pre_node[p]] = -flow[pre_node[p]][p];
            p = pre_node[p];
        }
    }
}

int main() 
{
    int i, j, d, ans;
    while (cin >> n >> m >> k, n || m || k) 
    {
        ans = 0;
        bool flag = false;
        for (i = 1; i <= n; i++) 
        {
            for (j = 1; j <= k; j++) 
            {
                cin >> capacity_need[i][j];
            }
        }
        for (i = 1; i <= m; i++) 
        {
            for (j = 1; j <= k; j++) 
            {
                cin >> capacity_have[i][j];
            }
        }
        for (i = 1; i <= k; i++) 
        {
            for (j = 1; j <= n; j++) 
            {
                for (d = 1; d <= m; d++) 
                {
                    cin >> construction_cost[i][d][j];
                }
            }
        }
        for (i = 1; i <= k; i++) 
        {
            memset(capacity, 0, sizeof(capacity));
            memset(flow, 0, sizeof(flow));
            memset(weight, 0, sizeof(weight));
            for (j = 1; j <= m; j++) 
            {
                capacity[0][j] = capacity_have[j][i]; 
            }
            for (j = 1; j <= n; j++) 
            {
                capacity[m + j][m + n + 1] = capacity_need[j][i];
            }
            for (j = 1; j <= m; j++) 
            {
                for (d = 1; d <= n; d++) 
                {
                    capacity[j][d + m] = capacity_have[j][i];
                }
            }
            for (j = 1; j <= m; j++) 
            {
                for (d = 1; d <= n; d++) 
                {
                    weight[j][d + m] = construction_cost[i][j][d];
                    weight[d + m][j] = -construction_cost[i][j][d];
                }
            }
            getMaxflow();
            for (j = 1; j <= n; j++) //查询是否满足每个店家的需求
            {
                if (capacity[j + m][n + m + 1] != flow[j + m][n + m + 1]) 
                {
                    flag = true;
                    break;
                }
            }
            if (flag) 
            {
                break;
            }
            for (j = 1; j <= m; j++) 
            {
                for (d = 1; d <= n; d++) 
                {
                    ans += flow[j][d + m] * weight[j][d + m]; 
                }
            }
        }
        if (flag) 
        {
            cout << -1 << endl;
        }
        else 
        {
            cout << ans << endl;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值