[
  {
    "path": ".gitignore",
    "content": "/spfa\n/gene\n/random\n/mcmf_scaling\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "# CMake 最低版本号要求\ncmake_minimum_required(VERSION 2.8)\n\n# 项目信息\nproject(cdn)\n\n# include路径\ninclude_directories(${PROJECT_SOURCE_DIR}/lib)\n\n# 设置可执行文件生成路径\nset(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/../bin)\n\n# 生成debug版本\nSET(CMAKE_BUILD_TYPE \"release\")\nif (CMAKE_BUILD_TYPE STREQUAL debug)\n    add_definitions(-D_DEBUG)\nendif ()\nSET(CMAKE_CXX_FLAGS_DEBUG \"$ENV{CXXFLAGS} -O0 -Wall -g -ggdb -std=c++11\")\nSET(CMAKE_CXX_FLAGS_RELEASE \"$ENV{CXXFLAGS} -O3 -Wall -D_DEBUG -g -std=c++11\")\n\n# 查找当前目录下的所有源文件\n# 并将名称保存到 DIR_LIB_SRCS 变量\naux_source_directory(. DIR_SRCS)\n\n# 指定生成目标\nadd_executable(cdn ${DIR_SRCS})\n"
  },
  {
    "path": "README.md",
    "content": "## 心路历程\n[2017华为软件精英挑战赛参赛心得](http://www.netcan666.com/2017/03/23/2017%E5%8D%8E%E4%B8%BA%E8%BD%AF%E4%BB%B6%E7%B2%BE%E8%8B%B1%E6%8C%91%E6%88%98%E8%B5%9B%E5%8F%82%E8%B5%9B%E5%BF%83%E5%BE%97/)\n"
  },
  {
    "path": "cdn.cpp",
    "content": "#include \"deploy.h\"\n#include \"lib_io.h\"\n#include \"lib_time.h\"\n#include \"stdio.h\"\n\nint main(int argc, char *argv[])\n{\n    print_time(\"Begin\");\n    char *topo[MAX_EDGE_NUM];\n    int line_num;\n\n    char *topo_file = argv[1];\n\n    line_num = read_file(topo, MAX_EDGE_NUM, topo_file);\n\n    printf(\"line num is :%d \\n\", line_num);\n    if (line_num == 0)\n    {\n        printf(\"Please input valid topo file.\\n\");\n        return -1;\n    }\n\n    char *result_file = argv[2];\n\n    deploy_server(topo, line_num, result_file);\n\n    release_buff(topo, line_num);\n\n    print_time(\"End\");\n\n\treturn 0;\n}\n\n"
  },
  {
    "path": "deploy.cpp",
    "content": "#include \"deploy.h\"\n#include <stdio.h>\n#include \"random.h\"\n#include \"mcmf.h\"\n#include \"gene.h\"\n\ntypedef void (sigFunc)(int);\nbool runing = true;\n\nsigFunc *\nSignal(int signo, sigFunc *func) {\n\tstruct sigaction\tact, oact;\n\tact.sa_handler = func;\n\tsigemptyset(&act.sa_mask);\n\tact.sa_flags = 0;\n\tif (sigaction(signo, &act, &oact) < 0)\n\t\treturn(SIG_ERR);\n\treturn(oact.sa_handler);\n}\n/* end signal */\n\nvoid timeOutHandler(int signo) {\n\truning = false;\n\treturn;\n}\n\n// 直连状态\nunordered_set<int> directConn() {\n\tstatic unordered_set<int> direct;\n\tif(direct.empty()) {\n\t\tfor(int u=0; u < mcmf.consumerNum; ++u)  // 初始位置，直连\n\t\t\tdirect.insert(mcmf.edges[mcmf.G[u + mcmf.networkNum][0]].to);\n\t}\n\treturn direct;\n}\n// XJBS\nbool cmp(int u1, int u2) { // 比较函数，消费降低需要的流量越低，排在越前\n\tint u1cap = 0, u2cap = 0;\n\tfor(size_t i = 0; i < mcmf.G[u1].size(); ++i)\n\t\tif(mcmf.isConsumer(mcmf.edges[mcmf.G[u1][i]].to)) {\n\t\t\tu1cap = mcmf.edges[mcmf.G[u1][i]].cap;\n\t\t\tbreak;\n\t\t}\n\n\tfor(size_t i = 0; i < mcmf.G[u2].size(); ++i)\n\t\tif(mcmf.isConsumer(mcmf.edges[mcmf.G[u2][i]].to)) {\n\t\t\tu2cap = mcmf.edges[mcmf.G[u2][i]].cap;\n\t\t\tbreak;\n\t\t}\n\n\treturn u1cap < u2cap;\n}\n\nunordered_set<int> XJBS(bool sorted = false) {\n\tunordered_set<int> init = directConn();\n\n\tvector<int> tmp(init.begin(), init.end());\n\tif(sorted) sort(tmp.begin(), tmp.end(), cmp);\n\tlist<int> cdn(tmp.begin(), tmp.end());\n\n\tint minCost = mcmf.minCost_Set(unordered_set<int>(cdn.begin(), cdn.end()));\n\n\t// 删点\n\tint iterationCnt = 0;\n\tfor(auto itr = cdn.begin(); itr != cdn.end(); ) {\n\t\tint node = *itr;\n\t\tint cost = -1;\n\t\titr = cdn.erase(itr);\n\t\t++iterationCnt;\n\t\tif( (cost = mcmf.minCost_Set(unordered_set<int>(cdn.begin(), cdn.end()))) < minCost && cost != -1) {\n\t\t\tminCost = cost;\n\t\t\t// printf(\"deleted: %d\\n\", node);\n\t\t}\n\t\telse {\n\t\t\titr = cdn.insert(itr, node); // 恢复\n\t\t\t++itr;\n\t\t}\n\t\t// printf(\"cost: %d\\n\", minCost);\n\t}\n\n\t// 替换\n\t/*\n\tfor(auto itr = cdn.begin(); itr != cdn.end(); ++itr) {\n\t\tint u = *itr;\n\t\tfor(size_t i = 0; i < mcmf.G[u].size(); ++i) {\n\t\t\tint cost = -1;\n\t\t\tint v = mcmf.edges[mcmf.G[u][i]].to;\n\t\t\tif(v < mcmf.networkNum) {\n\t\t\t\t*itr = v; // 替换\n\t\t\t\tif( (cost = mcmf.minCost_Set(unordered_set<int>(cdn.begin(), cdn.end()))) < minCost && cost != -1) {\n\t\t\t\t\tminCost = cost;\n\t\t\t\t\tprintf(\"replace %d with %d\\n\", u, v);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t*itr = u;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsize_t next = mcmf.G[u][i] + 1;\n\t\t\tif( next < mcmf.G[u].size() && mcmf.edges[next].to == v) ++i;\n\t\t}\n\t\t// printf(\"minCost: %d/%d\\n\", minCost, mcmf.consumerNum * mcmf.costPerCDN);\n\t}\n\t*/\n\n\t// printf(\"minCost: %d/%d iterationCnt: %d\\n\", minCost, mcmf.consumerNum * mcmf.costPerCDN, iterationCnt);\n\t// printf(\"cdn sz: %ld\\n\", cdn.size());\n\treturn unordered_set<int>(cdn.begin(), cdn.end());\n}\n\n// 按评估值从高到低选址\nunordered_set<int> evaluationSelect() {\n\tvector<pair<double, int>> evaluation;\n\tunordered_set<int> cdn{};\n\tfor(int u = 0; u < mcmf.networkNum; ++u)\n\t\tevaluation.push_back(make_pair(mcmf.nodes[u].evaluation, u));\n\tsort(evaluation.begin(), evaluation.end(), greater_equal<pair<double, int>>());\n\n\tfor(int i = 0; i < mcmf.networkNum; ++i) {\n\t\tcdn.insert(evaluation[i].second);\n\t\t// printf(\"%d: %lf\\n\", evaluation[i].second, evaluation[i].first);\n\t\tif(mcmf.minCost_Set(cdn) != -1) break;\n\t}\n\tmcmf.showRealMinCost();\n\treturn cdn;\n}\n\n//- GA begin\nint fitness(const Gene &p) { // 适应性\n\tint cost = mcmf.minCost_Set(p.to_Set());\n\t// printf(\"cost = %d\\n\", cost);\n\tint Total = mcmf.networkNum * mcmf.costPerCDN;\n\tif(cost == -1) return 1;\n\telse return max(1, Total - cost);\n}\n\n// 返回一个选中基因的下标\nint select(const vector<Gene> & genes) {\n\tdouble R = Rand.Random_Real(0, 1);\n\tdouble s = 0.0;\n\tfor(size_t i = 0; i < genes.size(); ++i) {\n\t\ts += genes[i].P;\n\t\t// printf(\"%f/%f\\n\", s, R);\n\t\tif(s >= R) {\n\t\t\t// printf(\"select %d\\n\", i);\n\t\t\treturn i;\n\t\t}\n\t}\n\treturn 0;\n}\n\nvoid GA(unordered_set<int> init = {}, int geneCnt = 20, double retain = 12, double crossP = 0.95, double mutationP = 0.25) { // 遗传算法\n\t// 初始基因数，精英保留(geneCnt-retain)，交叉率，变异率\n\tint iterationCnt = 0;\n\tint minCost = MCMF::INF;\n\n\tvector<Gene> genes(geneCnt);\n\tvector<Gene> next_genes(geneCnt);\n\tpriority_queue<Gene> que; // 最大堆选出最强的那20条染色体\n\tunordered_set<int> initial;\n\tif(init.empty()) initial = directConn();\n\telse initial = move(init);\n\n\t// 初始化基因\n\tgenes[0].set(initial, mcmf.networkNum);\n\n\tfor(int i = 1; i < geneCnt; ++i)\n\t\tgenes[i].reset(mcmf.networkNum);\n\n\n\twhile(runing && iterationCnt < 800) {\n\n\t\t// for(int i = 0; i < geneCnt; ++i) {\n\t\t\t// printf(\"基因型%d: \", i);\n\t\t\t// genes[i].show();\n\t\t// }\n\n\t\t// 适应度计算\n\t\tint sum = 0;\n\t\tfor(int i = 0; i < geneCnt; ++i) {\n\t\t\tgenes[i].fitness = fitness(genes[i]);\n\t\t\tsum += genes[i].fitness;\n\t\t\tminCost = min<double>(minCost, mcmf.networkNum * mcmf.costPerCDN - genes[i].fitness);\n\t\t\tque.push(genes[i]); // 最大堆\n\t\t}\n\n\t\tfor(int i = 0; i < geneCnt; ++i)\n\t\t\tgenes[i].P = genes[i].fitness*1.0 / sum;\n\n\t\tnext_genes.clear();\n\n\t\t// 选择\n\t\tfor(int i = 0; i < geneCnt; ++i) {\n\t\t\tif(que.size() > retain) next_genes[i] = que.top();\n\t\t\telse next_genes[i] = genes[select(genes)];\n\t\t\tque.pop();\n\t\t}\n\n\n\t\tfor(int i = 0; i < geneCnt; ++i) // 复制\n\t\t\tgenes[i] = next_genes[i];\n\n\t\t// XXOO\n\t\tfor(int i = 0; i < geneCnt; i+=2)\n\t\t\tif(Rand.Random_Real(0, 1) < crossP)\n\t\t\t\tgenes[i] * genes[i+1];\n\n\t\t// 突变\n\t\tfor(int i = 0; i < geneCnt; ++i)\n\t\t\tif(Rand.Random_Real(0, 1) < mutationP)\n\t\t\t\tgenes[i].mutation();\n\n\t\t++iterationCnt;\n\t\t// printf(\"iterationCnt: %d minCost = %d\\n\", iterationCnt, minCost);\n\t\t// break;\n\t}\n\n\t// mcmf.showSolution();\n\tprintf(\"iterationCnt=%d\\n\", iterationCnt);\n\t// printf(\"minCost: %d/%d\\n\\n\", minCost, mcmf.consumerNum * mcmf.costPerCDN);\n\tmcmf.showRealMinCost();\n}\n\n\n//- GA end\n\n//- 模拟退火 begin\nint select(const vector<pair<int, double>> & cdn) {\n\tdouble R = Rand.Random_Real(0, 1);\n\tdouble s = 0.0;\n\tfor(size_t i = 0; i < cdn.size(); ++i) {\n\t\ts += cdn[i].second;\n\t\t// printf(\"%f/%f\\n\", s, R);\n\t\tif(s >= R) {\n\t\t\t// printf(\"select %d\\n\", i);\n\t\t\treturn i;\n\t\t}\n\t}\n\treturn 0;\n}\nunordered_set<int> SA(unordered_set<int>init = {}, int innerLoop = 10, double T = 20.0, double delta = 0.99999, double poi = 0.02) { // 模拟退火，初始温度，迭代系数，0.15的增点概率\n\t// double T = 20.0, delta = 0.99999; // 初始温度20, 0.999-0.999999\n\n\tunordered_set<int> backup, cur, best;\n\n\tif(init.empty()) backup = directConn();\n\telse backup = move(init);\n\n\tint minCost = MCMF::INF, backCost = MCMF::INF, curCost = MCMF::INF;\n\tbackCost = mcmf.minCost_Set(backup);\n\tminCost = min(minCost, backCost);\n\n\tint iterationCnt = 0;\n\twhile(runing && T > 0.1) {\n\n\t\tfor(int loop = 0; loop < innerLoop && runing; ++loop) {\n\t\t\tvector<pair<int, double>> cdn; // cdn选中的概率，概率越大，越容易被选中\n\t\t\tdouble sum = 0.0;\n\t\t\tint u = -1, v = -1;\n\t\t\t// 随机选点u->v\n\t\t\tfor(auto x: backup)\n\t\t\t\tsum += mcmf.nodes[x].evaluation;\n\t\t\tfor(auto x: backup)\n\t\t\t\tcdn.push_back(make_pair(x, mcmf.nodes[x].evaluation / sum));\n\t\t\tu = cdn[select(cdn)].first;\n\n\t\t\tcdn.clear();\n\t\t\tsum = 0.0;\n\t\t\tfor(size_t i = 0; i < mcmf.G[u].size(); ++i) {\n\t\t\t\tint t = mcmf.edges[mcmf.G[u][i]].to;\n\t\t\t\tif(t < mcmf.networkNum)\n\t\t\t\t\tsum += 100000.0 / mcmf.nodes[t].evaluation;\n\t\t\t\t// printf(\"%d %lf\\n\", t, mcmf.nodes[t].evaluation);\n\t\t\t}\n\t\t\tfor(size_t i = 0; i < mcmf.G[u].size(); ++i) {\n\t\t\t\tint t = mcmf.edges[mcmf.G[u][i]].to;\n\t\t\t\tif(t < mcmf.networkNum)\n\t\t\t\t\tcdn.push_back(make_pair(t, (100000.0 / mcmf.nodes[t].evaluation) / sum));\n\t\t\t}\n\t\t\tv = cdn[select(cdn)].first;\n\n\n\t\t\tfor(int x: backup) {\n\t\t\t\tif(x == u) cur.insert(v);\n\t\t\t\telse cur.insert(x);\n\t\t\t}\n\n\t\t\tif(Rand.Random_Real(0, 1) < poi)\n\t\t\t\tcur.insert(Rand.Random_Int(0, mcmf.networkNum - 1)); // 增加一个点\n\n\t\t\tcurCost = mcmf.minCost_Set(cur);\n\n\t\t\tif(curCost == -1)  {// 无解\n\t\t\t\tcur.clear();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tint dC = curCost - backCost;\n\t\t\t\t// printf(\"dC: %d ratio: %lf probability: %lf\\n\", dC, curCost * 1.0 / minCost, exp(-dC / T));\n\t\t\t\tif(min(1.0, exp(-dC / T)) > Rand.Random_Real(0, 1))  {// 接受\n\t\t\t\t\t// printf(\"T: %lf dC: %d ratio: %lf\\n\", T, dC, curCost * 1.0 / minCost);\n\t\t\t\t\tbackup = move(cur);\n\t\t\t\t\tbackCost = curCost;\n\t\t\t\t} else {\n\t\t\t\t\tcur.clear();\n\t\t\t\t}\n\n\t\t\t\tif(minCost > backCost) {\n\t\t\t\t\tminCost = backCost;\n\t\t\t\t\tbest = backup;\n#ifdef _DEBUG\n\t\t\t\t\tprintf(\"T=%lf iterationCnt=%d\\n\", T, iterationCnt);\n\t\t\t\t\tmcmf.showRealMinCost();\n#endif\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tT *= delta;\n\t\t++iterationCnt;\n\n\t\t// printf(\"T=%lf iterationCnt=%d minCost = %d\\n\", T, iterationCnt, minCost);\n\t}\n\n#ifdef _DEBUG\n\tprintf(\"T=%lf iterationCnt=%d\\n\", T, iterationCnt);\n\tmcmf.showRealMinCost();\n#endif\n\t// printf(\"Deploy CDN(%ld):\\n\", backup.size());\n\t// for(int x: backup)\n\t\t// printf(\"%d \", x);\n\t// puts(\"\\n=====Solution======\");\n\t// mcmf.showSolution();\n\treturn best;\n}\n//- 模拟退火 end\n\n//- SAGA begin\nvoid SAGA(unordered_set<int>init = {}, double T = 20.0, double poi = 0.05, double delta = 0.999, int geneCnt = 26, double crossP = 0.95, double mutationP = 0.15) { // 模拟退火，初始温度，迭代系数\n\t// double T = 20.0, delta = 0.99999; // 初始温度20, 0.999-0.999999\n\n\tunordered_set<int> initial;\n\tvector<Gene> genes(geneCnt);\n\tvector<Gene> next_genes(geneCnt);\n\n\tif(init.empty()) initial = directConn();\n\telse initial = move(init);\n\n\tint minCost = MCMF::INF;\n\n\t// for(int i = 0; i < geneCnt; ++i)\n\t\t// genes[i].set(initial, mcmf.networkNum);\n\tgenes[0].set(initial, mcmf.networkNum);\n\tunordered_set<int> direct = directConn();\n\tfor(int i = 1; i < geneCnt; ++i)\n\t\tgenes[i].reset(mcmf.networkNum);\n\n\n\tint iterationCnt = 0;\n\t// 忘记初始化了！导致段错误！！\n\tGene elite{mcmf.networkNum}; // 精英基因\n\twhile(runing && T > 0.1) {\n\t\tnext_genes.clear();\n\t\tint fmin = MCMF::INF;\n\n\t\tfor(int idx = 0; runing && idx < geneCnt; ++idx) {\n\t\t\tunordered_set<int> s = genes[idx].to_Set(); // 每条染色体\n\t\t\tif(s.empty()) continue; // 空集的时候需要跳过\n\n\t\t\tint fi = mcmf.minCost_Set(s), fj;\n\t\t\tunordered_set<int> cur; // 邻域\n\t\t\t// 计算领域\n\n\t\t\t//- 随机选点u\n\t\t\tint u = -1;\n\t\t\tint i = Rand.Random_Int(0, s.size() - 1);\n\t\t\tauto it = s.begin();\n\t\t\tfor(; it != s.end() && i; ++it, --i);\n\t\t\tu = *it;\n\t\t\t// - 选完了\n\n\t\t\t// 随机选u->v\n\t\t\tint v = -1;\n\t\t\tdo {\n\t\t\t\tv = mcmf.edges[mcmf.G[u][Rand.Random_Int(0, mcmf.G[u].size() - 1)]].to; // (u, v)随机选点\n\t\t\t} while(v >= mcmf.networkNum); // 防止移动到消费节点\n\t\t\t// - 选完v了\n\n\t\t\tfor(int x: s) {\n\t\t\t\tif(x == u) cur.insert(v);\n\t\t\t\telse cur.insert(x);\n\t\t\t}\n\n\t\t\tif(Rand.Random_Real(0, 1) < poi)\n\t\t\t\tcur.insert(Rand.Random_Int(0, mcmf.networkNum - 1)); // 增加一个点\n\t\t\t// 邻域计算完毕\n\n\t\t\tfj = mcmf.minCost_Set(cur);\n\n\t\t\tif(fj != -1)  {// 有解\n\t\t\t\tint dC = fj - fi;\n\t\t\t\t// printf(\"dC: %d\\n\", dC);\n\t\t\t\tif(fi == -1 || min<double>(1, exp(-dC / T)) > Rand.Random_Real(0, 1)) {// 接受\n\t\t\t\t\tgenes[idx].set(cur, mcmf.networkNum);\n\t\t\t\t\tgenes[idx].fitness = fj;\n\t\t\t\t\tif(fmin > fj) {\n\t\t\t\t\t\tfmin = fj;\n\t\t\t\t\t\telite = genes[idx];\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tgenes[idx].fitness = fi; // 不接收\n\t\t\t\t\tif(fmin > fi) {\n\t\t\t\t\t\tfmin = fi;\n\t\t\t\t\t\telite = genes[idx];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else { // 无解，不接受\n\t\t\t\tif(fmin > fi && fi != -1) {\n\t\t\t\t\tfmin = fi;\n\t\t\t\t\telite = genes[idx];\n\t\t\t\t}\n\t\t\t\tgenes[idx].fitness = (fi == -1?mcmf.networkNum * mcmf.costPerCDN:fi);\n\t\t\t}\n\t\t}\n\n\t\t// 计算适应度\n\t\tdouble sum = 0.0;\n\t\tfor(int idx = 0; runing && idx < geneCnt; ++idx) {\n\t\t\tif(fmin == MCMF::INF) fmin = 0;\n\t\t\tint dC = genes[idx].fitness - fmin;\n\t\t\tgenes[idx].fitness = exp(-dC / T);\n\t\t\tsum += genes[idx].fitness;\n\t\t}\n\n\t\tfor(int idx = 0; runing && idx < geneCnt; ++idx)\n\t\t\tgenes[idx].P = genes[idx].fitness / sum;\n\n\t\t// 轮盘赌选择\n\t\tnext_genes[0] = elite; // 精英\n\n\t\tfor(int idx = 1; runing && idx < geneCnt; ++idx)\n\t\t\tnext_genes[idx] = genes[select(genes)];\n\n\t\tfor(int idx = 0; runing && idx < geneCnt; ++idx)\n\t\t\tgenes[idx] = next_genes[idx];\n\n\t\t// 洗牌，打乱顺序，考虑是否必要\n\t\t// random_shuffle(genes.begin(), genes.end());\n\t\t// XXOO\n\t\tfor(int i = 0; runing && i < geneCnt; i+=2)\n\t\t\tif(Rand.Random_Real(0, 1) < crossP)\n\t\t\t\tgenes[i] * genes[i+1];\n\n\t\t// 突变\n\t\tfor(int i = 0; runing && i < geneCnt; ++i)\n\t\t\tif(Rand.Random_Real(0, 1) < mutationP)\n\t\t\t\tgenes[i].mutation();\n\n\t\tif(fmin != 0) minCost = min(minCost, fmin);\n\t\tT *= delta;\n\n\t\t++iterationCnt;\n\t\t// printf(\"minCost: %d/%d\\n\\n\", minCost, mcmf.consumerNum * mcmf.costPerCDN);\n\t}\n\n\tprintf(\"T=%lf iterationCnt=%d\\n\", T, iterationCnt);\n\t// mcmf.showSolution();\n\t// printf(\"minCost: %d/%d\\n\\n\", minCost, mcmf.consumerNum * mcmf.costPerCDN);\n\tmcmf.showRealMinCost();\n}\n//- SAGA end\n\n//- 禁忌搜索 begin\n// 这块没写好，效果太差\nunordered_set<int> Tabu(unordered_set<int>init = {}, int times = MCMF::INF) { // 禁忌搜索\n\ttypedef unordered_set<int> X;\n\tlist<int> H; // 禁忌表，队列\n\n\tpair<int, X> x_best;\n\tX x_now;\n\tif(init.empty()) x_now = directConn();\n\telse x_now = move(init);\n\n\tpair<int, X> x_next{MCMF::INF, {}}; // 转移\n\tH.push_back(x_best.first = mcmf.minCost_Set(x_now));\n\n\t// for(int x: x_now)\n\t\t// printf(\"%d \", x);\n\t// puts(\"\");\n\n\tint iterationCnt = 0;\n\twhile(runing && iterationCnt < times) {\n\t\tint Len = 0;\n\t\tfor(int u: x_now) {\n\t\t\tfor(size_t i = 0; i < mcmf.G[u].size() && runing; i+=2) {\n\t\t\t\t++Len;\n\t\t\t\tint v = mcmf.edges[mcmf.G[u][i]].to; // u->v\n\t\t\t\tif(v < mcmf.networkNum) {\n\t\t\t\t\tX tmp{}; // 邻居\n\t\t\t\t\tfor(int uu: x_now) {\n\t\t\t\t\t\tif(uu != u) tmp.insert(uu);\n\t\t\t\t\t\telse tmp.insert(v);\n\t\t\t\t\t}\n\n\t\t\t\t\tint cost = mcmf.minCost_Set(tmp);\n\t\t\t\t\tif(cost == -1) continue;\n\n\t\t\t\t\tif(find(H.begin(), H.end(), cost) == H.end() && cost < x_next.first) {\n\t\t\t\t\t\tx_next.first = cost;\n\t\t\t\t\t\tx_next.second = move(tmp);\n\t\t\t\t\t\tif(x_best.first > cost) {\n\t\t\t\t\t\t\tx_best.first = cost;\n\t\t\t\t\t\t\tx_best.second = x_next.second;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tH.push_back(x_next.first); // 入队\n\t\tx_next.first = MCMF::INF;\n\t\tx_now = move(x_next.second);\n\t\t++iterationCnt;\n\t\twhile(H.size() > sqrt(Len)) H.pop_front();\n\t}\n\n\tprintf(\"iterationCnt = %d\\n\", iterationCnt);\n\tprintf(\"minCost: %d/%d cdnNum: %ld\\n\\n\", x_best.first, mcmf.consumerNum * mcmf.costPerCDN, x_best.second.size());\n\treturn x_best.second;\n}\n//- 禁忌搜索 end\n\n//- BPSO begin\n// 这个BPSO有坑，效果没想象中的好\ndouble sig(double v, double Vmax, double Vmin) { // v->[0, 1]\n\treturn 1/(1+ pow((Vmax - v)/(v- Vmin), 2));\n}\n\nvoid BPSO(unordered_set<int> init = {}, int particleCnt = 10, double Vmin = 0.0, double Vmax = 10.0, double c1 = 1.0, double c2 = 1.0) {\n\tvector<Particle> particles(particleCnt);\n\tParticle pBest, gBest;\n\tint fpBest = -1, fgBest = -1, fCur; // 当代最小费用，全局最小费用\n\tvector<double> v[particleCnt]; // Vij\n\tunordered_set<int> initial;\n\n\tif(init.empty()) initial = directConn(); // 初始状态\n\telse initial = move(init);\n\n\tfor(int i = 0; i < particleCnt; ++i) {\n\t\tif(i) particles[i].reset(mcmf.networkNum);\n\t\telse particles[i].set(initial, mcmf.networkNum); // 直连状态\n\n\t\tfor(int j = 0; j < mcmf.networkNum; ++j) // 初始化速度\n\t\t\tv[i].push_back(Vmin + (Vmax - Vmin) * Rand.Random_Real(0, 1));\n\t}\n\n\t// for(int i = 0; i < particleCnt; ++i)\n\t\t// for(int j = 0; j < mcmf.networkNum; ++j)\n\t\t\t// printf(\"%lf\\n\", v[i][j]);\n\n\n\tint iterationCnt = 0;\n\twhile(runing) {\n\t\tfor(int i = 0; i < particleCnt; ++i) {\n\t\t\tif( (fCur = mcmf.minCost_Set(particles[i].to_Set())) != -1) {\n\t\t\t\tif(fpBest == -1 || fpBest > fCur) {\n\t\t\t\t\tfpBest = fCur;\n\t\t\t\t\tpBest = particles[i];\n\t\t\t\t}\n\t\t\t\tif(fgBest == -1 || fgBest > fpBest) {\n\t\t\t\t\tfgBest = fpBest;\n\t\t\t\t\tgBest = pBest;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor(int i = 0; i < particleCnt; ++i) {\n\t\t\t// puts(\"------------------------\");\n\t\t\t// printf(\"p[%d]: \\n\", i);\n\t\t\t// particles[i].show();\n\t\t\tfor(int j = 0; j < mcmf.networkNum; ++j) {\n\t\t\t\tv[i][j] = v[i][j] +\n\t\t\t\t\tc1 * Rand.Random_Real(0, 1) * (pBest.getBit(j) - particles[i].getBit(j)) +\n\t\t\t\t\tc2 * Rand.Random_Real(0, 1) * (gBest.getBit(j) - particles[i].getBit(j));\n\t\t\t\tif(v[i][j] > Vmax) v[i][j] = Vmax;\n\t\t\t\telse if(v[i][j] < Vmin) v[i][j] = Vmin;\n\t\t\t\t// printf(\"sig(%lf) = %lf\\n\", v[i][j], sig(v[i][j], Vmax, Vmin));\n\n\t\t\t\tif(Rand.Random_Real(0, 1) < sig(v[i][j], Vmax, Vmin)) particles[i].setBit(j, 1);\n\t\t\t\telse particles[i].setBit(j, 0);\n\t\t\t}\n\t\t\t// particles[i].show();\n\t\t}\n\n\t\tfpBest = -1;\n\t\t++iterationCnt;\n\t\t// printf(\"iterationCnt = %d\\n\", iterationCnt);\n\t\t// printf(\"minCost: %d/%d\\n\", fgBest, mcmf.consumerNum * mcmf.costPerCDN);\n\t\t// break;\n\t}\n\n\tprintf(\"iterationCnt = %d\\n\", iterationCnt);\n\tprintf(\"minCost: %d/%d\\n\", fgBest, mcmf.consumerNum * mcmf.costPerCDN);\n}\n//- BPSO end\n\n\nvoid deploy_server(char * topo[MAX_EDGE_NUM], int line_num,char * filename)\n{\n\tSignal(SIGALRM, timeOutHandler);\n\t// 启动计时器\n\talarm(86);\n\tmcmf.loadGraph(topo, line_num);\n\n\tif(mcmf.networkNum < 800){\n\t\tmcmf.setCostCdnGap(80); // 不贪心降档\n\t\tunordered_set<int> s = SA(XJBS(true), 1, 500, 0.9999, 0.00);\n\t\t// mcmf.setCostCdnGap(1000); // 最后才贪心降档\n\t\t// mcmf.minCost_Set(s);\n\t\t// mcmf.showRealMinCost();\n\t\t// GA(XJBS(true));\n\t\t// SAGA(XJBS(true), 200, 0.00, 0.99, 20, 0.95, 0.05);\n\t} else {\n\t\tmcmf.setCostCdnGap(0); // 不贪心降档\n\t\tunordered_set<int> s = SA(XJBS(true), 1, 500, 0.9999, 0.00);\n\t\tmcmf.setCostCdnGap(1000); // 最后才贪心降档\n\t\tmcmf.minCost_Set(s);\n\t\tmcmf.showRealMinCost();\n\t}\n\n\n\t// SA(Tabu({}, 20));\n\t// GA(XJBS(true));\n\t// SAGA();\n\t// BPSO(XJBS(true));\n\t// XJBS();\n\n\t// 初始解{}，初始温度，增点概率，迭代系数，基因数，交叉率，变异率\n\t// if(mcmf.networkNum < 200) {\n\t\t// mcmf.setCostPerCdnMethod(false); // 动态变动\n\t\t// SAGA(XJBS(), 2000, 0.00, 0.99, 30, 0.8, 0.05);\n\t// }\n\t// else if(mcmf.networkNum < 500) {\n\t\t// mcmf.setCostPerCdnMethod(false); // 服务器费用固定\n\t\t// SAGA(XJBS(false), 2000, 0.00, 0.99, 50, 0.8, 0.05);\n\t// }\n\t// else {\n\t\t// mcmf.setCostPerCdnMethod(false); // 服务器费用固定\n\t\t// SAGA(XJBS(true), 20, 0.00, 0.999, 6, 0.8, 0.05);\n\t// }\n\n\t// unordered_set<int> cdn{\n\t\t// 0, 45, 55, 56, 60, 78, 105, 107, 133, 134, 142, 152, 161, 177, 236, 242, 245, 274, 278, 290, 291, 296, 314, 333, 343, 359, 373, 389, 390, 394, 409, 411, 416, 445, 458, 460, 467, 470, 495, 497, 515, 518, 526, 527, 538, 556, 557, 570, 577, 582, 586, 597, 615, 617, 625, 640, 641, 650, 656, 657, 666, 669, 683, 688, 697, 700, 714, 724, 751, 767, 804, 835, 847, 872, 883, 894, 920, 934, 940, 952, 970, 984, 991, 993, 1002, 1017, 1019, 1029, 1031, 1032, 1034, 1053, 1056, 1070, 1076, 1080, 1090, 1103, 1109, 1110, 1118, 1119, 1184, 1187\n\t// };\n\t// mcmf.setCostCdnGap(1000);\n\t// mcmf.minCost_Set(cdn);\n\t// mcmf.showRealMinCost();\n\n\n\t//- test\n\t/*\n\tdouble T = 20.0, delta = 0.99999, poi = 0.02;\n\tdouble bestT = T, bestDelta = delta, bestPoi = poi;\n\tint minCost = MCMF::INF;\n\tint cost = 0;\n\t// for(; T <= 100.0; T+=1) {\n\tfor(poi = 0.01; poi <= 1; poi += 0.01) {\n\t\talarm(88);\n\t\tif( (cost = SA({}, T,delta, poi)) < minCost && cost != -1) {\n\t\t\tminCost = cost;\n\t\t\tbestT = T;\n\t\t\tbestDelta = delta;\n\t\t\tbestPoi = poi;\n\t\t}\n\t\tputs(\"--------------------\");\n\t\tprintf(\"bestT = %lf/%lf bestDelta = %lf/%lf bestPoi = %lf/%lf minCost = %d\\n\", bestT, T, bestDelta, delta, bestPoi, poi, minCost);\n\t\tputs(\"--------------------\");\n\t\truning = true;\n\t}\n\t*/\n\t//- test End\n\n\t// 开始计算\n\twrite_result(mcmf.outputPath(), filename);\n\n}\n"
  },
  {
    "path": "deploy.h",
    "content": "#ifndef __ROUTE_H__\n#define __ROUTE_H__\n\n#include \"lib_io.h\"\n#include <signal.h>\n#include <unistd.h>\n#include <list>\n#include <algorithm>\n#include <cmath>\n#include <queue>\n#include <sys/types.h>\n#include <sys/wait.h>\n\nvoid deploy_server(char * graph[MAX_EDGE_NUM], int edge_num, char * filename);\n\n\n\n#endif\n"
  },
  {
    "path": "gene.h",
    "content": "/*************************************************************************\n\t> File Name: gene.cpp\n\t  > Author: Netcan\n\t  > Blog: http://www.netcan666.com\n\t  > Mail: 1469709759@qq.com\n\t  > Created Time: 2017-03-26 Sun 20:31:48 CST\n ************************************************************************/\n\n#ifndef __GENE__\n#define __GENE__\n#include <cstdio>\n#include <vector>\n#include <algorithm>\n#include <ctime>\n#include <bitset>\n#include <unordered_set>\n#include \"random.h\"\nusing namespace std;\n\nclass Gene {\n\tprivate:\n\t\tint len; // 长度，0-1200\n\t\tbitset<10000+5> code;\n\tpublic:\n\t\tdouble fitness; // 适应度/费用\n\t\tdouble P; // 选中概率\n\t\tGene(): len(0), code(), fitness(0), P(0) {}\n\t\tinline void reset(int len) { // 重置，亦即随机\n\t\t\tthis->len = len;\n\t\t\tthis->P = this->fitness = 0;\n\t\t\tfor(int i = 0; i < len; ++i)\n\t\t\t\tcode[i] = Rand.Random_Int(0, 1);\n\t\t}\n\n\t\tGene(int len): len(len), fitness(0), P(0) {}\n\n\t\tinline void operator*(Gene &b) { // 交叉，同时改变2条染色体\n\t\t\tint end = Rand.Random_Int(1, len); // 交换的位置，交换一边就行了，因为另一边不动，这里交换两边\n\t\t\tint begin = Rand.Random_Int(0, end - 1);\n\t\t\t// printf(\"begin = %d end = %d len = %d\\n\", begin, end, len);\n\t\t\tfor(int i = begin; i < end; ++i)\n\t\t\t\tif(code[i] != b.code[i]) {\n\t\t\t\t\tcode[i] = !code[i];\n\t\t\t\t\tb.code[i] = !b.code[i];\n\t\t\t\t}\n\t\t}\n\n\t\tinline void set(unordered_set<int> &s, int len) {\n\t\t\tthis->len = len;\n\t\t\tstd::vector<int> ss(s.begin(), s.end());\n\t\t\tsort(ss.begin(), ss.end()); // 排序\n\t\t\tsize_t j = 0;\n\t\t\tfor(int i = 0; i < len && j < ss.size(); ++i) {\n\t\t\t\tif(ss[j] == i) {\n\t\t\t\t\tcode[i] = 1;\n\t\t\t\t\t++j;\n\t\t\t\t} else // 忘记置0了\n\t\t\t\t\tcode[i] = 0;\n\t\t\t}\n\t\t}\n\n\t\tinline bool operator<(const Gene &b) const { // 最小堆用\n\t\t\treturn this->fitness < b.fitness;\n\t\t}\n\n\t\tinline void operator=(const Gene &b) { // 赋值\n\t\t\tthis->len = b.len;\n\t\t\tthis->fitness = b.fitness;\n\t\t\tthis->P = b.P;\n\t\t\tcode = b.code;\n\t\t}\n\t\tinline bool operator==(const Gene &b)const { // 判断序列是否相等\n\t\t\treturn code == b.code;\n\t\t}\n\n\t\tinline void mutation(int loc = -1) { // 突变，[0, len)\n\t\t\tif(loc == -1) loc = Rand.Random_Int(0, len - 1);\n\t\t\telse if(loc >= len) return;\n\t\t\t// printf(\"loc = %d\\n\", loc);\n\t\t\tcode[loc] = !code[loc];\n\t\t}\n\n\t\tinline void show() const {\n\t\t\tfor(int i = 0; i < len; ++i) {\n\t\t\t\tif(i != 0 && i % 8 == 0) printf(\",\");\n\t\t\t\tprintf(code[i]?\"1\":\"0\");\n\t\t\t}\n\t\t\tputs(\"\");\n\t\t}\n\n\t\tinline unordered_set<int> to_Set() const {\n\t\t\tunordered_set<int> S;\n\t\t\tfor(int i = 0; i < len; ++i)\n\t\t\t\tif(code[i]) S.insert(i);\n\t\t\treturn S;\n\t\t}\n\t\tinline bool getBit(int loc) {\n\t\t\treturn code[loc];\n\t\t}\n\t\tinline void setBit(int loc, bool x) {\n\t\t\tcode[loc] = x;\n\t\t}\n};\n\ntypedef Gene Particle;\n\n\n#endif\n\n\n// int main(void) {\n\t// Gene ga(10);\n\t// Gene gb(10);\n\n\t// ga.show();\n\t// gb.show();\n\t// ga * gb;\n\t// ga.show();\n\t// gb.show();\n\n\t// ga.show();\n\t// ga.mutation();\n\t// ga.show();\n\n\t// for(auto x: ga.to_Set()) {\n\t\t// printf(\"%d\\n\", x);\n\t// }\n\n\t// return 0;\n// }\n"
  },
  {
    "path": "io.cpp",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n#include <time.h>\n#include <sys/timeb.h>\n#include <errno.h>\n#include <unistd.h>\n#include <signal.h>\n\n#define MAX_LINE_LEN 55000\n\n#define INLINE  static __inline\n#ifdef _DEBUG\n#define PRINT   printf\n#else\n#define PRINT(...)\n#endif\n\n\nINLINE void write_file(const bool cover, const char * const buff, const char * const filename);\n\n\nvoid print_time(const char *head)\n{\n#ifdef _DEBUG\n    struct timeb rawtime;\n    struct tm * timeinfo;\n    ftime(&rawtime);\n    timeinfo = localtime(&rawtime.time);\n\n    static int ms = rawtime.millitm;\n    static unsigned long s = rawtime.time;\n    int out_ms = rawtime.millitm - ms;\n    unsigned long out_s = rawtime.time - s;\n    ms = rawtime.millitm;\n    s = rawtime.time;\n\n    if (out_ms < 0)\n    {\n        out_ms += 1000;\n        out_s -= 1;\n    }\n    printf(\"%s date/time is: %s \\tused time is %lu s %d ms.\\n\", head, asctime(timeinfo), out_s, out_ms);\n#endif\n}\n\nint read_file(char ** const buff, const unsigned int spec, const char * const filename)\n{\n    FILE *fp = fopen(filename, \"r\");\n    if (fp == NULL)\n    {\n    \tPRINT(\"Fail to open file %s, %s.\\n\", filename, strerror(errno));\n        return 0;\n    }\n    PRINT(\"Open file %s OK.\\n\", filename);\n\n    char line[MAX_LINE_LEN + 2];\n    unsigned int cnt = 0;\n    while ((cnt < spec) && !feof(fp))\n    {\n        line[0] = 0;\n        if (fgets(line, MAX_LINE_LEN + 2, fp) == NULL)  continue;\n        if (line[0] == 0)   continue;\n        buff[cnt] = (char *)malloc(MAX_LINE_LEN + 2);\n        strncpy(buff[cnt], line, MAX_LINE_LEN + 2 - 1);\n        buff[cnt][MAX_LINE_LEN + 1] = 0;\n        cnt++;\n    }\n    fclose(fp);\n    PRINT(\"There are %d lines in file %s.\\n\", cnt, filename);\n\n    return cnt;\n}\n\nvoid write_result(const char * const buff,const char * const filename)\n{\n\t// 以覆盖的方式写入\n    write_file(1, buff, filename);\n\n}\n\nvoid release_buff(char ** const buff, const int valid_item_num)\n{\n    for (int i = 0; i < valid_item_num; i++)\n        free(buff[i]);\n}\n\nINLINE void write_file(const bool cover, const char * const buff, const char * const filename)\n{\n    if (buff == NULL)\n        return;\n\n    const char *write_type = cover ? \"w\" : \"a\";//1:覆盖写文件，0:追加写文件\r\n    FILE *fp = fopen(filename, write_type);\n    if (fp == NULL)\n    {\n        PRINT(\"Fail to open file %s, %s.\\n\", filename, strerror(errno));\n        return;\n    }\n    PRINT(\"Open file %s OK.\\n\", filename);\n    fputs(buff, fp);\n    fputs(\"\\n\", fp);\n    fclose(fp);\n}\n\n"
  },
  {
    "path": "lib/lib_io.h",
    "content": "#ifndef __LIB_IO_H__\n#define __LIB_IO_H__\n\n#define MAX_EDGE_NUM    (2000 * 20)\n\n//读取文件并按行输出到buff。\n//buff为一个指针数组，每一个元素是一个字符指针，对应文件中一行的内容。\n//spec为允许解析的最大行数。\nextern int read_file(char ** const buff, const unsigned int spec, const char * const filename);\n\n//将result缓冲区中的内容写入文件，写入方式为覆盖写入\nextern void write_result(const char * const buff,const char * const filename);\n\n//释放读文件的缓冲区\nextern void release_buff(char ** const buff, const int valid_item_num);\n\n#endif\n\n"
  },
  {
    "path": "lib/lib_time.h",
    "content": "#ifndef __LIB_TIME_H__\n#define __LIB_TIME_H__\n\n//打印时间。入参为打印信息头\nvoid print_time(const char * const head);\n\n#endif\n"
  },
  {
    "path": "mcmf.cpp",
    "content": "/*************************************************************************\n  > File Name: spfa.cpp\n  > Author: Netcan\n  > Blog: http://www.netcan666.com\n  > Mail: 1469709759@qq.com\n  > Created Time: 2017-03-21 Tue 21:25:20 CST\n ************************************************************************/\n\n#include \"mcmf.h\"\n\nchar MCMF::topo[50000*1000*6];\n\nvoid MCMF::getPath(int cost) {\n\tif(cost != -1 && cost < solutionPath.first) {\n\t\tsolutionPath.first = cost;\n\t\tsolutionPath.second.clear(); // 记得清理\n\t\tvector<int> tmpPath;\n\t\tmemset(vis, 0, sizeof(vis[0]) * Vn);\n\t\tfindPath(tmpPath, superSource, INF, INF);\n\t}\n\n}\n\nint MCMF::findPath(vector<int> & tmpPath, int u, int minFlow, int totalFlow) { // dfs，深搜路径，路径上的最小流量，总流量\n\tif(vis[u]) return 0;\n\telse if(isConsumer(u)) { // 到达消费节点，找到一条路径\n\t\tsolutionPath.second.push_back(tmpPath);\n\t\tvector<int> &b = solutionPath.second.back();\n\t\tb.push_back(u - networkNum); // 转换为消费节点的id\n\t\tb.push_back(minFlow);\n\t\tb.push_back(servers[nodes[b.front()].bestCdnId].level); // 档次\n\t\treturn minFlow;\n\t}\n\n\tvis[u] = true;\n\tif(u < superSource) tmpPath.push_back(u);\n\n\tint tf = totalFlow;\n\tfor(size_t i = 0; i < G[u].size(); ++i) {\n\t\tEdge &e = edges[G[u][i]];\n\t\tif(e.flow > 0) { // 流过的流量>0\n\t\t\t// printf(\"%d->%d flow: %d\\n\", e.from, e.to, e.flow);\n\t\t\tint v = e.to;\n\t\t\tif(!vis [v]) {\n\t\t\t\tif(totalFlow > 0) {\n\t\t\t\t\tint t = findPath(tmpPath, v,\n\t\t\t\t\t\t\tmin(minFlow, min(totalFlow, e.flow)),\n\t\t\t\t\t\t\tmin(totalFlow, e.flow));\n\t\t\t\t\te.flow -= t;\n\t\t\t\t\ttotalFlow -= t;\n\t\t\t\t}\n\t\t\t\telse break;\n\t\t\t}\n\t\t}\n\t}\n\n\tvis[u] = false;\n\tif(u < superSource) tmpPath.pop_back();\n\treturn tf;\n}\n\nint MCMF::aug(int u, int minFlow, int &tmpCost, int &cost) {\n\tif(u == superSink) { // 到达终点\n\t\tcost += tmpCost * minFlow;\n\t\treturn minFlow;\n\t}\n\tvis[u] = true;\n\tint tf = minFlow;\n\tfor(size_t i = 0; i < G[u].size(); ++i) {\n\t\tEdge &e = edges[G[u][i]];\n\t\tif( (e.cap - e.flow) && !e.cost && !vis[e.to]) {\n\t\t\tint d = aug(e.to, min(tf, (e.cap - e.flow)), tmpCost, cost);\n\t\t\te.flow += d;\n\t\t\tedges[G[u][i] ^ 1].flow -= d;\n\t\t\ttf -= d;\n\t\t\tif(! tf) return minFlow;\n\t\t}\n\t}\n\treturn minFlow - tf;\n}\n\nbool MCMF::modLabel(int &tmpCost) {\n\tint d = INF;\n\tfor(int u=0; u < Vn; ++u) // 遍历完全部节点\n\t\tif(vis[u]) {\n\t\t\tfor(size_t i = 0; i < G[u].size(); ++i) {\n\t\t\t\tEdge &e = edges[G[u][i]];\n\t\t\t\tif( (e.cap - e.flow) && !vis[e.to] && e.cost < d)\n\t\t\t\t\td = e.cost;\n\t\t\t}\n\t\t}\n\tif(d == INF) return false;\n\n\tfor(int u=0; u < Vn; ++u)\n\t\tif(vis[u]) {\n\t\t\tfor(size_t i = 0; i < G[u].size(); ++i) {\n\t\t\t\tedges[G[u][i]].cost -= d;\n\t\t\t\tedges[G[u][i] ^ 1].cost += d;\n\t\t\t}\n\t\t}\n\ttmpCost += d;\n\treturn true;\n\n\t// SLF优化\n\t/*\n\tmemset(d, 0x3f, sizeof(int) * Vn);\n\td[superSink] = 0;\n\tstatic deque<int> que; que.push_back(superSink);\n\twhile(que.size())\n\t{\n\t\tint dt, u = que.front(); que.pop_front();\n\t\tfor(size_t i = 0; i < G[u].size(); ++i) {\n\t\t\tEdge &e = edges[G[u][i]], &re = edges[G[u][i] ^ 1];\n\t\t\tif( (re.cap - re.flow) && (dt = d[u] - e.cost) < d[e.to] )\n\t\t\t\t(d[e.to] = dt) <= d[que.size() ? que.front() : 0]\n\t\t\t\t\t? que.push_front(e.to) : que.push_back(e.to);\n\t\t}\n\t}\n\tfor(int u=0; u<=superSink; ++u)\n\t\tfor(size_t i = 0; i < G[u].size(); ++i) {\n\t\t\tEdge &e = edges[G[u][i]];\n\t\t\te.cost += d[e.to] - d[u];\n\t\t}\n\n\ttmpCost += d[superSource];\n\treturn d[superSource] < INF;\n\t*/\n}\n\n\n\nvoid MCMF::AddEdge(int from, int to, int cap, int cost) {\n\tedges.push_back(Edge(to, cap, 0, cost));\n\tedges.push_back(Edge(from, 0, 0, -cost));\n\n\tint m = edges.size();\n\tG[from].push_back(m - 2);\n\tG[to].push_back(m - 1);\n\n\tif(from < networkNum) {\n\t\tif(isConsumer(to))  // 网络节点直连消费节点，计算需要的总共流量\n\t\t\tneedFlow += cap;\n\t\tif(to < superSource)\n\t\t\tnodes[from].nodeFlow += cap;\n\t}\n}\n\n\nvoid MCMF::showSolution() const{\n\tint totalFlow = 0;\n\tfor(const auto &x : solutionPath.second) {\n\t\tfor(vector<int>::const_iterator i = x.begin(); i != x.end() - 1; ++i) {\n\t\t\tif(i == x.begin()) printf(\"%d\", *i);\n\t\t\telse printf(\"->%d\", *i);\n\t\t}\n\t\ttotalFlow += x.back();\n\t\tprintf(\" flow: %d\\n\", x.back());\n\t}\n\tprintf(\"Flow :%d/%d Cost: %d/%d\\n\", totalFlow, needFlow, solutionPath.first, costPerCDN * consumerNum);\n}\n\nvoid MCMF::loadGraph(char * topo[MAX_EDGE_NUM], int line_num) {\n\tsscanf(topo[0], \"%d%d%d\", &networkNum, &edgeNum, &consumerNum); // 网络节点数量 网络链路数量 消费节点数量\n\n\t// solutionPath.first = consumerNum * costPerCDN; // 待求\n\n\tsuperSource = consumerNum + networkNum; // 超级源点、汇点\n\tsuperSink = consumerNum + networkNum + 1;\n\tVn = superSink + 1;\n\n\tint a, b, c, d, maxCap = 0;\n\tint i;\n\tfor(i = 2; i < line_num && !isspace(topo[i][0]); ++i) {\n\t\tsscanf(topo[i], \"%d%d%d\", &a, &b, &c); // 服务器硬件档次ID 输出能力 硬件成本\n\t\tservers.push_back(Server(a, b, c));\n\t\t// printf(\"level: %d outFlow: %d cost: %d\\n\", a, b, c);\n\t}\n\t// printf(\"maxFlowServer level: %d outFlow: %d cost: %d\\n\", maxFlowServer.level, maxFlowServer.outFlow, maxFlowServer.cost);\n\n\tfor(++i; i < line_num && !isspace(topo[i][0]); ++i) {\n\t\tsscanf(topo[i], \"%d%d\", &a, &b); // 网络节点ID 部署成本\n\t\tnodes[a].deployCost = b;\n\t\t// printf(\"node: %d cost: %d\\n\", a, b);\n\t}\n\n\tfor(++i; i < line_num && !isspace(topo[i][0]); ++i) {\n\t\tsscanf(topo[i], \"%d%d%d%d\", &a, &b, &c, &d); // 链路起始节点ID 链路终止节点ID 总带宽大小 单位网络租用费\n\t\tAddEdge(a, b, c, d);\n\t\tAddEdge(b, a, c, d);\n\t\t// printf(\"u: %d v: %d bandwidth: %d cost: %d\\n\", a, b, c, d);\n\t}\n\n\tfor(++i; i < line_num; ++i) {\n\t\tsscanf(topo[i], \"%d%d%d\", &a, &b, &c); // 消费节点ID 相连网络节点ID 视频带宽消耗需求\n\t\tAddEdge(b, a + networkNum, c, 0); // 与网络节点相连\n\t\tAddEdge(a + networkNum, superSink, c, 0); // 与汇点相连\n\t\tmaxCap = max(maxCap, c);\n\t\t// printf(\"consumer: %d connect: %d need: %d\\n\", a, b, c);\n\n\t\t// vector<int> path{to, from, bandwidth}; // 直连策略\n\t\t// solutionPath.second.push_back(move(path));\n\t}\n\tsort(servers.begin(), servers.end());\n\tmaxFlowServer = servers.back();\n\t// vector<Server>::iterator it;\n\t// if( (it = lower_bound(servers.begin(), servers.end(), maxCap))  != servers.end()) // >= 最大档\n\t\t// maxFlowServer = *it; // 存放下标，nodes输出路径的时候用\n\t// else maxFlowServer = servers.back(); // 最大的level\n\t// printf(\"l: %d\\n\", maxFlowServer.level);\n\n\tcostPerCDN = maxFlowServer.cost; // 以最大档次的费用为准\n\tedgeNum = edges.size(); // 边数\n\tsolutionPath.first = INF;\n\tcalcEvaluation();\n}\n\nconst char* MCMF::outputPath() {\n\t// getPath(solutionPath.first, true); // 放到最后才遍历路径，提高性能\n\t// showRealMinCost();\n\n\tchar buffer[10];\n\tchar *pt = topo, *pb = buffer;\n\tsnprintf(buffer, sizeof(buffer), \"%ld\\n\\n\", solutionPath.second.size());\n\twhile(*pb && (*pt++ = *pb++));\n\tfor(auto &x: solutionPath.second) {\n\t\tfor(auto it = x.begin(); it != x.end(); ++it) {\n\t\t\tsnprintf(buffer, sizeof(buffer), it == x.begin() ? \"%d\":\" %d\", *it);\n\t\t\tpb = buffer;\n\t\t\twhile(*pb && (*pt++ = *pb++));\n\t\t}\n\t\t*pt++ = '\\n';\n\t}\n\t*--pt = 0;\n\treturn topo;\n}\n\nMCMF mcmf;\n\n"
  },
  {
    "path": "mcmf.h",
    "content": "/*************************************************************************\n\t> File Name: spfa.h\n\t  > Author: Netcan\n\t  > Blog: http://www.netcan666.com\n\t  > Mail: 1469709759@qq.com\n\t  > Created Time: 2017-03-22 Wed 12:33:02 CST\n ************************************************************************/\n#ifndef __MCMF__\n#define __MCMF__\n\n#include <cstdio>\n#include <assert.h>\n#include <cstring>\n#include <algorithm>\n#include <cctype>\n#include <cstdlib>\n#include <deque>\n#include <vector>\n#include <unordered_set>\n#include <unordered_map>\n#include \"deploy.h\"\nusing namespace std;\n\n\nextern bool runing;\n\nclass MCMF{\n\tprivate:\n\t\tstruct Edge{\n\t\t\tint to, cap, flow ,cost, oldCost;\n\t\t\tEdge() {}\n\t\t\tEdge(int to, int cap, int flow, int cost): to(to), cap(cap), flow(flow), cost(cost), oldCost(cost) {}\n\t\t};\n\t\tstruct Server {\n\t\t\tint level, outFlow, cost;\n\t\t\tServer(int level, int outFlow, int cost): level(level), outFlow(outFlow), cost(cost) {}\n\t\t\tServer() {\n\t\t\t\tlevel = outFlow = cost = 0;\n\t\t\t}\n\t\t\tbool operator<(const Server &b) const {\n\t\t\t\tif(this->outFlow != b.outFlow) return this->outFlow < b.outFlow;\n\t\t\t\telse return this->cost < b.cost;\n\t\t\t}\n\t\t\tbool operator<(int flow) const {\n\t\t\t\treturn this->outFlow < flow;\n\t\t\t}\n\t\t};\n\n\t\tstatic const int N = 20000+5;\n\t\tstatic char topo[50000*1000*6]; // 网络路径数量不得超过300000条, 单条路径的节点数量不得超过10000个, 所有数值必须为大于等于0的整数，数值大小不得超过1000000。\n\n\t\tint Vn, superSource, superSink; // 总节点数，超级源点/汇点，需要的流量\n\t\tsize_t minCostCdnGap = 50; // 当cdn小于这个数的时候，进行贪心降档\n\t\tint d[N];\n\t\tbool vis[N]; // 标记数组\n\t\tvector<Server> servers; // 服务器\n\t\tServer maxFlowServer;\n#ifdef _DEBUG\n\t\tint realMinCost = INF; // 保存真实的最小费用，最后打印，调试用\n#endif\n\n\t\tpair<int, vector<vector<int>>> solutionPath; // 当前可行解，路径\n\n\t\t// ZKW算法\n\t\tint aug(int u, int minFlow, int &tmpCost, int &cost);\n\t\tbool modLabel(int &tmpCost);\n\n\t\tinline void reset() { // 还原初始状态，删除源点\n\t\t\tfor(size_t i = 0; i < G[superSource].size(); ++i)\n\t\t\t\tG[edges[G[superSource][i]].to].pop_back(); // 删除链接超源的边\n\t\t\tfor(int i=G[superSource].size() * 2; i > 0; --i) edges.pop_back(); // 删除超源的边\n\t\t\tfor(size_t i = 0; i < edges.size(); ++i) {\n\t\t\t\tedges[i].cost = edges[i].oldCost;\n\t\t\t\tedges[i].flow = 0; // 重置流量\n\t\t\t}\n\t\t\tG[superSource].clear();\n\t\t}\n\t\tinline void calcEvaluation() { // 评估函数，评估值越小越好\n\t\t\tfor(int u = 0; u < networkNum; ++u)\n\t\t\t\tnodes[u].evaluation =  nodes[u].deployCost * 100 / nodes[u].nodeFlow;\n\t\t}\n\n\t\tint findPath(vector<int> & tmpPath, int u, int minFlow, int totalFlow);\n\t\tvoid getPath(int cost);\n\t\tinline int pathFlowCost() { // 路径流量费\n\t\t\tint cost = 0, flow = 0;\n\t\t\tint tmpCost = 0;\n\t\t\tdo {\n\t\t\t\tint f;\n\t\t\t\tdo {\n\t\t\t\t\tmemset(vis, 0, sizeof(vis[0]) * Vn);\n\t\t\t\t\tf = aug(superSource, INF, tmpCost, cost);\n\t\t\t\t\tflow += f;\n\t\t\t\t}\n\t\t\t\twhile(f);\n\t\t\t}\n\t\t\twhile(modLabel(tmpCost));\n\t\t\tif(flow < needFlow) return -1;\n\t\t\treturn cost;\n\n\t\t\t// SLF优化\n\t\t\t/*\n\t\t\t   while(modLabel(tmpCost))\n\t\t\t   do bzero(vis, sizeof(vis));\n\t\t\t   while(aug(superSource, INF, tmpCost, cost));\n\t\t\t*/\n\t\t}\n\n\t\tinline int minCost(const unordered_set<int> &cdn) { // 调用setCDN后再调用minCost!! 注意不能连续调用多次minCost!!!\n\t\t\tint cost = pathFlowCost(), cdnCost = 0, cdnFlow = 0, minCdnFlowCost = INF;\n\t\t\tif(cost == -1) return -1;\n\n\t\t\tvector<pair<int, int>> diff; // 存放差/节点名\n\t\t\tunordered_map<int, int> eId; // 存放超源到cdn的边的下标\n\t\t\tbool downShift = false;\n\t\t\tif(cdn.size() < minCostCdnGap) downShift = true;\n\n\t\t\tfor (size_t i = 0; i < G[superSource].size(); i++) { // 降档\n\t\t\t\tEdge &e = edges[G[superSource][i]];\n\t\t\t\tif(e.flow == 0) continue;\n\n\t\t\t\tvector<Server>::iterator it;\n\t\t\t\tif( (it = lower_bound(servers.begin(), servers.end(), e.flow))  != servers.end()) // >= 降档\n\t\t\t\t\tnodes[e.to].bestCdnId = it - servers.begin(); // 存放下标，nodes输出路径的时候用\n\t\t\t\telse nodes[e.to].bestCdnId = servers.size() - 1; // 最大的level\n\n\t\t\t\tif(downShift) {\n\t\t\t\t\teId[e.to] = G[superSource][i];\n\t\t\t\t\te.cap = servers[nodes[e.to].bestCdnId].outFlow;\n\t\t\t\t\tcdnFlow += servers[nodes[e.to].bestCdnId].outFlow; // 计算总费用\n\t\t\t\t}\n\t\t\t\tcdnCost += servers[nodes[e.to].bestCdnId].cost; // 计算总费用\n\t\t\t\t// printf(\"%d e.flow: %d/%d(%d)\\n\", e.to, e.flow, servers[nodes[e.to].bestCdnId].outFlow, servers[nodes[e.to].bestCdnId].level);\n\t\t\t}\n\t\t\tminCdnFlowCost = min(minCdnFlowCost, cost + cdnCost); // 更新总费用\n\t\t\t// printf(\"minCdnFlowCost %d\\n\", minCdnFlowCost);\n\n\t\t\tif(downShift) {\n\t\t\t\tbool exit = false;\n\n\t\t\t\twhile(! exit) {\n\t\t\t\t\tdiff.clear();\n\t\t\t\t\tfor (size_t i = 0; i < G[superSource].size(); i++) {\n\t\t\t\t\t\tconst Edge &e = edges[G[superSource][i]];\n\t\t\t\t\t\tif(e.flow == 0) continue;\n\t\t\t\t\t\t// printf(\"u: %d e.flow: %d/%d(%d)\\n\", e.to, e.flow, servers[nodes[e.to].bestCdnId].outFlow, servers[nodes[e.to].bestCdnId].level);\n\n\t\t\t\t\t\tif(nodes[e.to].bestCdnId  == 0) diff.push_back(make_pair(0, e.to));\n\t\t\t\t\t\telse if(e.flow == servers[nodes[e.to].bestCdnId - 1].outFlow) { // 直接可以降档\n\t\t\t\t\t\t\tdiff.push_back(make_pair(INF, e.to));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse diff.push_back(make_pair(\n\t\t\t\t\t\t\t\t\t(servers[nodes[e.to].bestCdnId].cost - servers[nodes[e.to].bestCdnId - 1].cost) /\n\t\t\t\t\t\t\t\t\t(e.flow - servers[nodes[e.to].bestCdnId - 1].outFlow)\n\t\t\t\t\t\t\t\t\t, e.to));\n\t\t\t\t\t}\n\t\t\t\t\tsort(diff.begin(), diff.end(), greater<pair<int, int>>());\n\n\t\t\t\t\tfor(size_t i = 0; i < diff.size(); ++i) {\n\t\t\t\t\t\tint u = diff[i].second;\n\t\t\t\t\t\tif(nodes[u].bestCdnId == 0) continue;\n\t\t\t\t\t\tfor(size_t j = 0; j < edges.size(); ++j) {\n\t\t\t\t\t\t\tedges[j].cost = edges[j].oldCost;\n\t\t\t\t\t\t\tedges[j].flow = 0; // 重置流量\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tint dc = servers[nodes[u].bestCdnId].cost - servers[nodes[u].bestCdnId - 1].cost;\n\t\t\t\t\t\tint df = servers[nodes[u].bestCdnId].outFlow - servers[nodes[u].bestCdnId - 1].outFlow;\n\t\t\t\t\t\tif(cdnFlow - df >= needFlow) { // 预判\n\t\t\t\t\t\t\tcdnCost -= dc; // 更新Cdn费用\n\t\t\t\t\t\t\tcdnFlow -= df;\n\t\t\t\t\t\t\tedges[eId[u]].cap = servers[nodes[u].bestCdnId - 1].outFlow;\n\t\t\t\t\t\t\t--nodes[u].bestCdnId;\n\t\t\t\t\t\t\tcost = pathFlowCost();\n\n\t\t\t\t\t\t\tif(cost == -1 || cost + cdnCost > minCdnFlowCost) { // 降档失败\n\t\t\t\t\t\t\t\tcdnCost += dc;\n\t\t\t\t\t\t\t\tcdnFlow += df;\n\t\t\t\t\t\t\t\tedges[eId[u]].cap = servers[nodes[u].bestCdnId + 1].outFlow;\n\t\t\t\t\t\t\t\t++nodes[u].bestCdnId;\n\t\t\t\t\t\t\t\tif(cost == -1){\n\t\t\t\t\t\t\t\t\texit = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {// 降档成功，有解\n\t\t\t\t\t\t\t\tminCdnFlowCost = cost + cdnCost;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t// printf(\"success: %d\\n\", u);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}  else {\n\t\t\t\t\t\t\texit = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// printf(\"minCdnFlowCost %d\\n\", minCdnFlowCost);\n\t\t\t\t\t// printf(\"%d diff: %d\\n\", u, diff[i].first);\n\t\t\t\t\t// printf(\"cdnFlow: %d cdnCost: %d needFlow: %d minCdnFlowCost: %d\\n\", cdnFlow, cdnCost, needFlow, minCdnFlowCost);\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t\tcost = minCdnFlowCost;\n\n\n\t\t\t// 计算部署费用\n#ifdef _DEBUG\n\t\t\tint realCost = cost;\n#endif\n\t\t\tfor(auto c: cdn) {\n\t\t\t\tcost += nodes[c].deployCost;\n#ifdef _DEBUG\n\t\t\t\trealCost += nodes[c].deployCost;\n#endif\n\t\t\t}\n\n#ifdef _DEBUG\n\t\t\trealMinCost = min(realMinCost, realCost);\n#endif\n\n\t\t\tif(cost < solutionPath.first) {\n\t\t\t\tif(downShift) {\n\t\t\t\t\tfor(size_t j = 0; j < edges.size(); ++j) {\n\t\t\t\t\t\tedges[j].cost = edges[j].oldCost;\n\t\t\t\t\t\tedges[j].flow = 0; // 重置流量\n\t\t\t\t\t}\n\t\t\t\t\tpathFlowCost();\n\t\t\t\t}\n\n\t\t\t\t// 打印档次\n\t\t\t\t/*\n\t\t\t\tvector<pair<int,int>> v;\n\t\t\t\tfor (size_t i = 0; i < G[superSource].size(); i++) { // 降档\n\t\t\t\t\tEdge &e = edges[G[superSource][i]];\n\t\t\t\t\tv.push_back(make_pair(e.to, G[superSource][i]));\n\t\t\t\t}\n\t\t\t\tsort(v.begin(), v.end());\n\n\t\t\t\tfor(size_t i = 0; i < v.size(); ++i) {\n\t\t\t\t\tEdge &e =  edges[v[i].second];\n\t\t\t\t\t// printf(\"%d e.flow: %d/%d(%d)\\n\", e.to, e.flow, servers[nodes[e.to].bestCdnId].outFlow, servers[nodes[e.to].bestCdnId].level);\n\t\t\t\t\tprintf(\"%d\\t%d\\n\", e.to, servers[nodes[e.to].bestCdnId].level);\n\t\t\t\t}\n\t\t\t\t*/\n\t\t\t\tgetPath(cost); // 更新方案\n\t\t\t}\n\t\t\treturn cost;\n\t\t}\n\n\n\t\tinline void setCdn(const unordered_set<int> & cdn) {\n\t\t\treset();\n\t\t\tfor(int x: cdn)\n\t\t\t\tAddEdge(superSource, x, maxFlowServer.outFlow, 0);\n\t\t}\n\tpublic:\n\t\tstruct Node{\n\t\t\tint deployCost; // 节点部署费用\n\t\t\tint nodeFlow; // 每个节点的流量\n\t\t\tint bestCdnId; // 存放每个节点最适合的服务器档次（下标）\n\t\t\tdouble evaluation; // 每个节点的评估值\n\t\t\tNode() {\n\t\t\t\tdeployCost = bestCdnId = nodeFlow = evaluation = 0;\n\t\t\t}\n\t\t} nodes[10000 + 5];\n\n\t\tvector<int> G[N]; // 图\n\t\tvector<Edge> edges; // 边集\n\t\tint networkNum, edgeNum, consumerNum, needFlow, costPerCDN = 0;\n\t\tstatic const int INF = 0x3f3f3f3f;\n\t\tfriend class MCMF_SCALING;\n\n\t\tvoid inline showRealMinCost() {\n#ifdef _DEBUG\n\t\t\tprintf(\"\\x1B[31mReal minCost: %d/%d\\x1B[0m\\n\", realMinCost, consumerNum * costPerCDN);\n#endif\n\t\t}\n\n\t\tinline bool isConsumer(int u) {\n\t\t\treturn u >= networkNum && u < superSource;\n\t\t}\n\n\n\t\tMCMF() {\n\t\t\tneedFlow = 0;\n\t\t};\n\t\tinline void setCostCdnGap(int x) {\n\t\t\tminCostCdnGap = x;\n\t\t}\n\t\tvoid AddEdge(int from, int to, int cap, int cost);\n\t\tvoid showSolution() const;\n\t\tvoid loadGraph(char * topo[MAX_EDGE_NUM], int line_num);\n\t\tconst char* outputPath();\n\n\n\t\tinline int minCost_Set(const unordered_set<int> &cdn) {\n\t\t\tsetCdn(cdn);\n\t\t\treturn minCost(cdn);\n\t\t}\n\n};\nextern MCMF mcmf;\n\n#endif\n"
  },
  {
    "path": "random.h",
    "content": "/*************************************************************************\n\t> File Name: random.cpp\n\t  > Author: Netcan\n\t  > Blog: http://www.netcan666.com\n\t  > Mail: 1469709759@qq.com\n\t  > Created Time: 2017-03-27 Mon 07:40:54 CST\n ************************************************************************/\n\n#ifndef __RANDOM__\n#define __RANDOM__\n#include <cstdio>\n#include <random>\n\nclass Random {\n\tprivate:\n\t\tstd::default_random_engine generator;\n\n\tpublic:\n\t\t// Random(time_t t = time(NULL)): generator(t) {}\n\t\tinline uint32_t Random_Int(uint32_t min, uint32_t max) { // [min, max]\n\t\t\treturn std::uniform_int_distribution<uint32_t>{min, max}(generator);\n\t\t}\n\t\tinline double Random_Real(double min, double max) { // [min, max)\n\t\t\treturn std::uniform_real_distribution<double>{min, max}(generator);\n\t\t}\n};\nRandom Rand;\n\n#endif\n"
  },
  {
    "path": "testBranch.txt",
    "content": "hello world\nnetcan\n\n"
  }
]