节约里程法的C#实现
节约里程法需求因素有三个:车辆容量 节点需求量 两两点对间最短距离
节约里程法具体原理不 做详述,此处采用清华大学出版社《运筹学》第四版(非本科生版)P536-P538页所所讲述算法实现;
如下图所示:
具体代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
namespace Save_Distance
{
public class Save_Distance
{
//创建线路结构体,包含节约里程,起点,终点
public struct path
{
public double save_diatance;
public int head;
public int tail;
}
//路径规划算法
public static ArrayList find_path(double whole_capacity, ArrayList demand, double[,] minpath)
{
double real_capacity = whole_capacity;
//对站点需求量进行预处理;如果该站点需求量大于车辆整车容量,则直接减去该整车容量;
// double capacity = 3;
//将节点需求量数据保存到ArryList当中
// ArrayList demand = new ArrayList();
// demand.Add(0.6); demand.Add(2.6); demand.Add(12.3); demand.Add(3.4);
int i, j;
ArrayList route_result = new ArrayList();
ArrayList planed_node = new ArrayList();
/*
double[,] minpath = new double[100, 100];
minpath[0, 0] = 12; minpath[0, 1] = 3.6; minpath[0, 2] = 6.6; minpath[0, 3] = 13.6;
minpath[1, 0] = 7.7; minpath[1, 1] = 21.7; minpath[1, 2] = 0.9;
minpath[2, 0] = 3.7; minpath[2, 1] = 49.7;
minpath[3, 0] = 8.7;
*/
//计算节约里程,将数据保存到struct path类型的ArryList当中
ArrayList Save_distance = new ArrayList();
for (i = 0, j = 0; minpath[i, 0] != 0; i++)
{
for (j = 0; minpath[i, j + 1] != 0; j++)
{
path p;
p.head = i;
p.tail = i + j + 1;
p.save_diatance = (minpath[0, i] + minpath[0, i + j + 1] - minpath[i + 1, j]);
Save_distance.Add(p);
}
}
//对Save_distance 按照save_distance进行递减排序;
for (i = 0; i < Save_distance.Count; i++)
{
for (j = 0; j < Save_distance.Count - i - 1; j++)
{
path x = (path)Save_distance[j];
path y = (path)Save_distance[j + 1];
path temp_jiedian;
if (x.save_diatance < y.save_diatance)
{ temp_jiedian = (path)Save_distance[j]; Save_distance[j] = (path)Save_distance[j + 1]; Save_distance[j + 1] = temp_jiedian; }
}
}
//寻找节约里程,将其保存到Arrylist 当中;
//确保所有节点都被正确规划;
while (planed_node.Count != demand.Count)
{
double capacity = real_capacity;
ArrayList plan_path = new ArrayList();
//如果当前还有未添加的单个节点,但此时线路全被删除完毕,则单独规划一条路径;
if (Save_distance.Count == 0)
{
for (i = 0; i < demand.Count; i++)
{
if (!planed_node.Contains(i))
{
planed_node.Add(i);
plan_path.Add(i);
route_result.Add(plan_path);
break;
}
}
}
else
{
//寻找可能的起始线路(节约里程尽可能的大,且路线上下标满足节点要求);
foreach (path innitial in Save_distance)
{
if ((double)demand[innitial.head] + (double)demand[innitial.tail] < capacity)
{
plan_path.Add(innitial.head);
plan_path.Add(innitial.tail);
capacity -= ((double)demand[innitial.head] + (double)demand[innitial.tail]);
break;
}
}
//如果当前节点中未能找到初始路线,则表明当前所有的节点都应当单独设置为一条路径
if (plan_path.Count == 0)
{
for (i = 0; i < demand.Count; i++)
{
if (!planed_node.Contains(i))
{
ArrayList many_path = new ArrayList();
many_path.Add(i);
planed_node.Add(i);
route_result.Add(many_path);
}
}
}
else
{
//遍历所有节点;
//如果当前线路中有head或者tail中有一个值等于plan_path的头,并且该点需求量满足车辆容量限制,则将tail或者head添加到plan_path的头部
//如果当前线路中有head或者tail中有一个值等于plan_path的尾,则将tail或者head添加到plan_path的尾部
//一旦找到一条符合要求的,则需要重新回到起点,从头遍历;
int bianli = 0;
while (bianli < Save_distance.Count)
{
foreach (path temppath in Save_distance)
{
if (temppath.head == (int)plan_path[0] && !plan_path.Contains(temppath.tail) && (double)demand[temppath.tail] <= capacity)
{
plan_path.Insert(0, temppath.tail);
//获取尾部的需求量,更新车辆剩余容量;
capacity -= (double)demand[temppath.tail];
break;
}
else if (temppath.head == (int)plan_path[plan_path.Count - 1] && !plan_path.Contains(temppath.tail) && (double)demand[temppath.tail] <= capacity)
{
plan_path.Add(temppath.tail);
capacity -= (double)demand[temppath.tail];
break;
}
else if (temppath.tail == (int)plan_path[0] && !plan_path.Contains(temppath.head) && (double)demand[temppath.head] <= capacity)
{
plan_path.Insert(0, temppath.head);
capacity -= (double)demand[temppath.head];
break;
}
else if (temppath.tail == (int)plan_path[plan_path.Count - 1] && !plan_path.Contains(temppath.head) && (double)demand[temppath.head] <= capacity)
{
plan_path.Add(temppath.head);
capacity -= (double)demand[temppath.head];
break;
}
}
bianli += 1;
}
//将所有节点添加到已规划节点中;
foreach (int node in plan_path)
{
planed_node.Add(node);
}
route_result.Add(plan_path);
//找出一条线路后,删除已经不可能的线路;
for (i = 0; i < plan_path.Count; i++)
{
for (j = 0; j < Save_distance.Count; j++)
{
path temp = (path)Save_distance[j];
if (temp.head == (int)plan_path[i] || temp.tail == (int)plan_path[i])
{
Save_distance.Remove(temp);
j -= 1;
}
}
}
}
}
}
foreach (ArrayList my_path in route_result)
{
foreach (int node in my_path)
{
Console.WriteLine(node);
}
Console.WriteLine("another");
}
Console.WriteLine("结束");
return route_result;
}
static void Main(string[] args)
{
// find_path();
Console.ReadLine();
}
}
}