91、最小生成树

数据集

Capacitated minimal spanning tree

kruskal与prim算法(均为精确算法)

pro = """
(1)  capmst1
------------------------------------------------------------------------

This file contains tc (central depot) and te data (end depot)
for the CMST with unit demands.

L. Gouveia, A comparison of directed formulations for the
capacitated minimal spanning tree problem, Telecommunication
Systems vol 1, 1993, 51-76.

Each vertex i (i=1,...n) has unit weight and each subtree connected to the 
depot N (N=n+1) in the final solution should have a total weight of less than 
or equal to Q.

For each problem type (tc,te), there are 10 problems each, 5 of size n=40
and 5 of size n=80.  Note that the depot is vertex number 41 and 81
respectively.

For size n=40 (N=41) : tc40-*.txt and te40-*.txt (*=1,...,5)
capacity Q can take three values: Q=3, 5, or 10.
Total number of problems = 2*5*3 = 30 (15 type tc and 15 type te).

For size n=80 (N=81) : tc80-*.txt and te80-*.txt (*=1,...,5)
capacity Q can take three values: Q=5, 10, or 20.
Total number of problems = 2*5*3 = 30 (15 type tc and 15 type te).

The format of the file is as follows:

problem name
problem size n
edge costs c(i,j), i=1,N, j=1,N

(Note c(i,i) is taken as a large number)


(2) capmst2
-----------------------------------------------------------------------

Whereas the tc and te problems satisfy the triangle inequality,
the cm problems contained in capmst2 do not.
Moreover, the problems are not of unit weight.

There are three problem sizes N=50,100, 200
(Note that n=49, 99, 199 respectively, with the depot located
at vertex N).

For each problem size, there are 5 problems each.

For each problem cm**_r*.data (**=50,100,200, *=1,...5), there
is a weight file called priz**_r.dat containing the weight of each
vertex q(i), i=1,...,n.

a- The capmst2 file contains:
name of the weight file
vertex weights q(i), i=1,n (N-1)
-------------------------------
b- name of the problem
size of the problem given by N
edge costs c(i,j), i=1,N, j=1,N
--------------------------------
Part b is repeated for the same problem size (starting with N=50)
then part a re-appears for the next problem size (ie, N=100)
and so on for N=200.

(Note that c(i,i) here is given a zero value)

For all problem sizes, Q can take three values:
Q=200, 400 or 800

Total number of problems = 3*5*3 = 45
-----------------------------------
Update: 25th September 2003 
Ricardo Fukasawa ([email protected]) has pointed 
out that the tc/te 80 files appear to be flawed, in that
they should correspond to symmetric cost matrices, and they are not
symmetric.
He has supplied what are believed to be correct versions of these files,
together with a number of other data files - these are all available
in the zipped file capmstnew.zip
"""

import pyscipopt
import re
import time

#记录每个函数执行的时间
loop = 1
def timeLog(f):
    def wrapper(*args, **kw):
        global loop
        now = time.perf_counter()
        res = f(*args, **kw)
        print("%s-%s:"%(loop, f.__name__), time.perf_counter()-now)
        loop += 1
        return res
    return wrapper

class Case:

    def __init__(self, name, n, M):
        self.name = name
        self.n = n
        self.M = M

    def __repr__(self):
        return str([self.name, self.n, self.M])

def dataRead():
    data_path1 = r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmst1.txt"
    data_path2 = r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmst2.txt"
    data_paths = [r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/tc80-1.dat",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/tc80-2.dat",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/tc80-3.dat",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/tc80-4.dat",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/tc80-5.dat",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/tc120-1.dat",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/tc160-1.dat",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TC4001.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TC4002.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TC4003.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TC4004.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TC4005.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TC4006.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TC4007.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TC4008.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TC4009.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TC40010.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/te80-1.dat",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/te80-2.dat",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/te80-3.dat",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/te80-4.dat",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/te80-5.dat",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/te120-1.dat",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/te160-1.dat",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TE4001.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TE4002.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TE4003.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TE4004.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TE4005.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TE4006.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TE4007.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TE4008.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TE4009.DAT",
                  r"/Users/zhangchaoyu/PycharmProjects/pythonProject/OR_Library/CapacitatedMinimalSpanningTree/data/capmstnew/TE40010.DAT"]

    cases = []
    # 先读名称和规模,然后一直读数,知道碰到"-"就终止该问题的存储,并开启下一个的存储
    f = open(data_path1)
    row = f.readline().replace('\n', '').strip()
    while row != "":
        name = row
        n = int(f.readline())+1
        L = []
        row = f.readline().replace('\n', '').strip()
        while row[0] != "-":
            L += [int(w) for w in re.split(" ", row)]
            row = f.readline().replace('\n', '').strip()
        M = {(i, j): L[n * i + j] for i in range(n) for j in range(n)}
        cases.append(Case(name, n, M))
        row = f.readline().replace('\n', '').strip()

    #2
    f = open(data_path2)
    row = f.readline().replace('\n', '').strip()
    while row != "":
        name = row
        if name[:4] == 'priz':
            row = f.readline().replace('\n', '').strip()
            while row[0] != "-":
                row = f.readline().replace('\n', '').strip()
            name = f.readline().replace('\n', '').strip()
        n = int(f.readline())
        L = []
        row = f.readline().replace('\n', '').strip()
        while row[0] != "-":
            L += [int(w) for w in re.split(" ", row)]
            row = f.readline().replace('\n', '').strip()
        M = {(i, j): L[n * i + j] for i in range(n) for j in range(n)}
        cases.append(Case(name, n, M))
        row = f.readline().replace('\n', '').strip()

    #3
    for path in data_paths:
        f = open(path)
        row = f.readline().replace('\n', '').strip()
        row = [int(w) for w in re.split(" ", row) if w != ""]
        n = row[0]
        #开始读cij
        L = []
        row = f.readline().replace('\n', '').strip()
        while row != "":
            L += [int(w) for w in re.split(" ", row) if w != ""]
            row = f.readline().replace('\n', '').strip()
        M = {(i, j): L[n * i + j] for i in range(n) for j in range(n)}
        cases.append(Case(re.split("/", path)[-1], n, M))

    return cases

#保证aij=aji,否则kruskal与prim结果不一致,prim会偏大一些
def casesClean(cases):
    for case in cases:
        for k in case.M:
            s,t = k[0], k[1]
            valueMin = min(case.M[s,t], case.M[t,s])
            case.M[s, t] = valueMin
            case.M[t, s] = valueMin


#将边从小到大排,直到长到一起
# 1    F := 空集合
# 2    for each 图 G 中的顶点 v
# 3        do 将 v 加入森林 F
# 4    所有的边(u, v) ∈ E依权重 w 递增排序
# 5    for each 边(u, v) ∈ E
# 6        do if u 和 v 不在同一棵子树
# 7            then F := F ∪ {(u, v)}
# 8                将 u 和 v 所在的子树合并
@timeLog
def kruskal(case):
    #每个点初始化为一个集合
    points = {i:{i} for i in range(case.n)}
    #边按权重排序
    edges = [[k[0], k[1], v] for k,v in case.M.items()]
    edges.sort(key=lambda e:e[2])
    #
    edgesUsed = []
    for e in edges:
        start, end = e[0], e[1]
        #如果start和end不在一起,则合并
        if end not in points[start]:
            edgesUsed.append(e)
            SNew = points[start]|points[end]
            for p in SNew:
                points[p] = SNew
        #边够了直接退出
        if len(edgesUsed) == case.n-1:
            break
    return edgesUsed

#从任意一点开始,逐步找最短的边向外扩充
@timeLog
def prim(case):
    S = {0}
    T = {i for i in range(1, case.n)}
    edgesUsed = []
    while len(S) < case.n:
        edges = [[k[0], k[1], v] for k, v in case.M.items() if k[0] in S and k[1] in T]
        edges.sort(key=lambda e:e[2])
        e = edges[0]
        S.add(e[1])
        T.remove(e[1])
        edgesUsed.append(e)
    return edgesUsed

def runOne(case):
    edgesUsedKruskal = kruskal(case)
    wMinKruskal = sum([e[2] for e in edgesUsedKruskal])
    edgesUsedPrim = prim(case)
    wMinPrim = sum([e[2] for e in edgesUsedPrim])
    print("kruskal: ", wMinKruskal)
    print("prim: ", wMinPrim)
    return wMinKruskal, wMinPrim

def runALl(cases):
    L = []
    for case in cases:
        L.append(runOne(case))
    return L


if __name__ == '__main__':
    cases = dataRead()
    casesClean(cases)
    #runOne
    # case = cases[-1]
    # wMinKruskal, wMinPrim = runOne(case)
    #runAll
    L = runALl(cases)


你可能感兴趣的:(运筹优化,机器学习基础算法实现,python,算法)