仓库选址(二维前缀和,距离和问题)

仓库选址

链接
牛能在某小城有了固定的需求,为了节省送货的费用,他决定在小城里建一个仓库,但是他不知道选在哪里,可以使得花费最小。
给出一个m \times nm×n的矩阵,代表下一年小城里各个位置对货物的需求次数。我们定义花费为货车载货运输的距离,货车只能沿着水平或竖直方向行驶。

输入描述:

首先在一行中输入T ,T≤10,代表测试数据的组数。
每组输入在第一行给出两个正整数n, m,1≤n,m≤100,分别代表矩阵的宽和高。
接下来m行,每行n个不超过1000的数字,代表矩阵里的元素。

输出描述:

每组输入在一行中输出答案。

输入

3
2 2
1 1
1 0
4 4
0 8 2 0
1 4 5 0
0 1 0 1
3 9 2 0
6 7
0 0 0 0 0 0
0 1 0 3 0 1
2 9 1 2 1 2
8 7 1 3 4 3
1 0 2 2 7 7
0 1 0 0 1 0
0 0 0 0 0 0

输出

2
55
162

备注:

送货时只能单次运输,若该位置需要3次,货车必须跑3次。
即使该位置需要被送货,我们仍然可以选择该位置作为仓库。

算法分析

这道题的数据比较弱,可以暴力解决,正解的话,会用到二维前缀和,二维前缀和的做法比如我们当前在(x,y)选为仓库,当(x,y+1)选为仓库的时候,那么左上角为(1,1)到右下角(n,y)的子矩阵到该点的距离都增加了 1,而左上角为(x,y+1)到右下角(n,m)的子矩阵就减少了 1.减少或增加的总距离就是子矩阵的前缀和.所以我们算出(1,1)到(n,m)的代价和,之后移动点,算出最小距离

代码实现

暴力做法

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<math.h>
using namespace std;
const int maxn=1e2+5;
typedef long long ll;
int t,n,m;
int map[maxn][maxn];
int dis,res;
int slove(int x,int y)
{
    dis=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            dis+=map[i][j]*(abs(x-i)+abs(y-j));
        }
    }
    return dis;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        res=0x3f3f3f3f;
        scanf("%d%d",&m,&n);
        memset(map,0,sizeof(map));
        for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++)
              scanf("%d",&map[i][j]);
        for(int i=1;i<=n;i++)
           for(int j=1;j<=m;j++)
           {
              int a=slove(i,j);
              res=min(res,a);
           }
        cout<<res<<endl;
    }
    return 0;
}

二维前缀和做法

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<math.h>
using namespace std;
const int maxn=1e2+5;
typedef long long ll;
int t,n,m;
int map[maxn][maxn];
int s[maxn][maxn];
int dis,res;
int col(int a,int b,int c,int d)
{
    return s[c][d]-s[a-1][d]-s[c][b-1]+s[a-1][b-1];
}
int main()
{
    cin>>t;
    while(t--)
    {
        int tot=0;
        cin>>m>>n;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                cin>>map[i][j];
                tot+=map[i][j]*(i-1+j-1);
                s[i][j]=s[i][j-1]+s[i-1][j]+map[i][j]-s[i-1][j-1];
            }
        int res=0x3f3f3f3f;
        int tt;
        for(int i=1;i<=n;i++)
        {
            tt=tot;
            res=min(res,tt);
            for(int j=1;j<=m;j++)
            {
                res=min(tt,res);
                tt+=col(1,1,n,j)-col(1,j+1,n,m);
            }
            tot+=col(1,1,i,m)-col(i+1,1,n,m);
        }
        cout<<res<<endl;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
双层遗传算法(Two-Layer Genetic Algorithm, TLGA)是一种结合了两个层次的遗传操作的优化方法,通常用于解决复杂的组合优化问题,如选址和配送问题。这类问题涉及到在多个可能的地点选择服务设施,并决定每个设施如何分配货物或服务给客户,以达到最小化成本或满足特定的服务水平。 在MATLAB中使用双层遗传算法来求解选址和配送问题,你可以按照以下步骤进行: 1. **问题定义**:明确问题的输入(例如,客户位置、需求量、运输距离、设施容量等)、目标函数(如总运输成本或满足所有客户需求的时间)和约束条件(如每个设施的最大服务范围)。 2. **编码设计**:将问题变量编码为染色体,比如设施的选择作为一层,配送策略作为另一层。每一代的染色体表示一个可能的解决方案。 3. **初始化种群**:生成初始的随机种群,包含多个不同的解决方案。 4. **适应度评估**:计算每个个体的适应度,即目标函数值。适应度好的个体在选择过程中更有可能被保留。 5. **选择操作**:使用双层选择,第一层选择设施,第二层基于选定的设施执行配送策略选择。 6. **交叉与变异**:在父代的基础上,通过交叉和变异操作产生新的解,增加种群多样性。 7. ** elitism**:保持一部分最佳解,保证算法在搜索过程中的稳定性。 8. **迭代过程**:重复上述步骤,直到达到预设的代数或适应度达到满意水平。 9. **解的输出**:返回具有最优适应度的解,即选址和配送方案。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值