CFLP问题的贪心算法和模拟退火法解决方案

用贪心算法和模拟退货法解决CFLP问题

首先问题描述如下:

给定n个工厂和m个顾客,开工厂需要一定的费用,一个工厂有一定的容量限制,每个顾客也有一定的需求,而每个顾客要选取某个工厂也需要一定的分配费用,现在要求找出一个分配方案,把顾客分配给不同的工厂,然后在可以满足所有顾客需求的前提下让所有的花费(开工厂的花费和分配的花费)最小。

这显然是一个NP-hard问题,因为情况数非常的多,而且也没有什么固定的好的策略,所以现在我们就用贪心算法和模拟退火法两种方法来解决这个问题。

一、贪心算法

这个问题如果用贪心算法做的话思路应该是很简单的,就直接一个顾客一个顾客这样来选择工厂,然后在每次的选取过程中保证这个顾客的花费最小即可,但是这样做的话就会带来一个问题,就是开工厂的费用问题,如果把开工厂的费用都归到一个顾客的花费上的话,那么这个顾客要选取一个新工厂的花费就会很高,那么如果每个顾客采取这个策略就会都不愿意开新工厂,那么实际上就会去选取那些已经被其他顾客开的工厂。但是实际上开工厂的钱应该是要平摊到选取了这个工厂的所有顾客头上的,因此这样的策略显然不是太好。所以为了优化这个问题,我们可以在贪心的过程中直接不考虑开工厂的价钱(虽然这样做其实也没有符合很精确的开工厂的钱的平摊,但是因为在遍历过程中我们没办法确认后面的顾客会怎么选取工厂,所以只能退而求其次),然后在最后再看哪些工厂被选取了,然后再加上开这部分工厂的价钱即可,所以贪心部分的代码如下:

void CFLPSolver::beginGreedy()
{
    //对每个顾客执行贪心策略
    for(int i = 0; i < customerNum; i++)
    {
        int select = -1;
        int curCost = 99999999;
        //选取分配费用最小的工厂
        for(int j = 0; j < facilityNum; j++)
        {
            if(demand[i] <= capacityLeft[j])
            {
                //int newCost = (1 - open[j]) * openCost[j] + allocateCost[j][i];
                int newCost = allocateCost[j][i];
                if(newCost < curCost)
                {
                    select = j;
                    curCost = newCost;
                }
            }
        }
        //没有工厂可以选取了,说明这个样例的工厂的容量比较紧张,不能用简单的贪心策略做,不过在我测试的71个样例中都没有发现问题
        if(select == -1)
        {
            cout << "greedy failed" << endl;
        }
        //选取工厂,更新工厂的剩余容量,开启被选取的工厂,加上分配的费用
        else
        {
            allocate[i] = select;
            capacityLeft[select] -= demand[i];
            open[select] = 1;
            finalCost += curCost;
        }
    }
    //加上开工厂的费用
    for(int i = 0; i < facilityNum; i++)
    {
        if(open[i])
        {
            finalCost += openCost[i];
        }
    }
}

而对样例的结果测试如下(这里只列出最终的cost和运行时间,具体的结果见文末的github连接):

instance cost time(ms)
p1 9440 9
p2 8126 7
p3 10126 10
p4 12126 6
p5 9375 15
p6 8061 0
p7 10061 16
p8 12061 0
p9 9040 15
p10 7726 16
p11 9726 0
p12 11726 21
p13 12032 14
p14 9180 3
p15 13180 16
p16 17180 15
p1
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值