Repository: netcan/2017-HUAWEI-Codecraft
Branch: master
Commit: ff32fa385da9
Files: 15
Total size: 41.0 KB
Directory structure:
gitextract_mkuby_3i/
├── .gitignore
├── CMakeLists.txt
├── README.md
├── cdn.cpp
├── deploy.cpp
├── deploy.h
├── gene.h
├── io.cpp
├── lib/
│ ├── lib_io.h
│ └── lib_time.h
├── mcmf.cpp
├── mcmf.h
├── random.h
├── testBranch.txt
└── 初赛样例参数分析.xlsx
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/spfa
/gene
/random
/mcmf_scaling
================================================
FILE: CMakeLists.txt
================================================
# CMake 最低版本号要求
cmake_minimum_required(VERSION 2.8)
# 项目信息
project(cdn)
# include路径
include_directories(${PROJECT_SOURCE_DIR}/lib)
# 设置可执行文件生成路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/../bin)
# 生成debug版本
SET(CMAKE_BUILD_TYPE "release")
if (CMAKE_BUILD_TYPE STREQUAL debug)
add_definitions(-D_DEBUG)
endif ()
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb -std=c++11")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall -D_DEBUG -g -std=c++11")
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(cdn ${DIR_SRCS})
================================================
FILE: README.md
================================================
## 心路历程
[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/)
================================================
FILE: cdn.cpp
================================================
#include "deploy.h"
#include "lib_io.h"
#include "lib_time.h"
#include "stdio.h"
int main(int argc, char *argv[])
{
print_time("Begin");
char *topo[MAX_EDGE_NUM];
int line_num;
char *topo_file = argv[1];
line_num = read_file(topo, MAX_EDGE_NUM, topo_file);
printf("line num is :%d \n", line_num);
if (line_num == 0)
{
printf("Please input valid topo file.\n");
return -1;
}
char *result_file = argv[2];
deploy_server(topo, line_num, result_file);
release_buff(topo, line_num);
print_time("End");
return 0;
}
================================================
FILE: deploy.cpp
================================================
#include "deploy.h"
#include <stdio.h>
#include "random.h"
#include "mcmf.h"
#include "gene.h"
typedef void (sigFunc)(int);
bool runing = true;
sigFunc *
Signal(int signo, sigFunc *func) {
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (sigaction(signo, &act, &oact) < 0)
return(SIG_ERR);
return(oact.sa_handler);
}
/* end signal */
void timeOutHandler(int signo) {
runing = false;
return;
}
// 直连状态
unordered_set<int> directConn() {
static unordered_set<int> direct;
if(direct.empty()) {
for(int u=0; u < mcmf.consumerNum; ++u) // 初始位置,直连
direct.insert(mcmf.edges[mcmf.G[u + mcmf.networkNum][0]].to);
}
return direct;
}
// XJBS
bool cmp(int u1, int u2) { // 比较函数,消费降低需要的流量越低,排在越前
int u1cap = 0, u2cap = 0;
for(size_t i = 0; i < mcmf.G[u1].size(); ++i)
if(mcmf.isConsumer(mcmf.edges[mcmf.G[u1][i]].to)) {
u1cap = mcmf.edges[mcmf.G[u1][i]].cap;
break;
}
for(size_t i = 0; i < mcmf.G[u2].size(); ++i)
if(mcmf.isConsumer(mcmf.edges[mcmf.G[u2][i]].to)) {
u2cap = mcmf.edges[mcmf.G[u2][i]].cap;
break;
}
return u1cap < u2cap;
}
unordered_set<int> XJBS(bool sorted = false) {
unordered_set<int> init = directConn();
vector<int> tmp(init.begin(), init.end());
if(sorted) sort(tmp.begin(), tmp.end(), cmp);
list<int> cdn(tmp.begin(), tmp.end());
int minCost = mcmf.minCost_Set(unordered_set<int>(cdn.begin(), cdn.end()));
// 删点
int iterationCnt = 0;
for(auto itr = cdn.begin(); itr != cdn.end(); ) {
int node = *itr;
int cost = -1;
itr = cdn.erase(itr);
++iterationCnt;
if( (cost = mcmf.minCost_Set(unordered_set<int>(cdn.begin(), cdn.end()))) < minCost && cost != -1) {
minCost = cost;
// printf("deleted: %d\n", node);
}
else {
itr = cdn.insert(itr, node); // 恢复
++itr;
}
// printf("cost: %d\n", minCost);
}
// 替换
/*
for(auto itr = cdn.begin(); itr != cdn.end(); ++itr) {
int u = *itr;
for(size_t i = 0; i < mcmf.G[u].size(); ++i) {
int cost = -1;
int v = mcmf.edges[mcmf.G[u][i]].to;
if(v < mcmf.networkNum) {
*itr = v; // 替换
if( (cost = mcmf.minCost_Set(unordered_set<int>(cdn.begin(), cdn.end()))) < minCost && cost != -1) {
minCost = cost;
printf("replace %d with %d\n", u, v);
}
else {
*itr = u;
}
}
size_t next = mcmf.G[u][i] + 1;
if( next < mcmf.G[u].size() && mcmf.edges[next].to == v) ++i;
}
// printf("minCost: %d/%d\n", minCost, mcmf.consumerNum * mcmf.costPerCDN);
}
*/
// printf("minCost: %d/%d iterationCnt: %d\n", minCost, mcmf.consumerNum * mcmf.costPerCDN, iterationCnt);
// printf("cdn sz: %ld\n", cdn.size());
return unordered_set<int>(cdn.begin(), cdn.end());
}
// 按评估值从高到低选址
unordered_set<int> evaluationSelect() {
vector<pair<double, int>> evaluation;
unordered_set<int> cdn{};
for(int u = 0; u < mcmf.networkNum; ++u)
evaluation.push_back(make_pair(mcmf.nodes[u].evaluation, u));
sort(evaluation.begin(), evaluation.end(), greater_equal<pair<double, int>>());
for(int i = 0; i < mcmf.networkNum; ++i) {
cdn.insert(evaluation[i].second);
// printf("%d: %lf\n", evaluation[i].second, evaluation[i].first);
if(mcmf.minCost_Set(cdn) != -1) break;
}
mcmf.showRealMinCost();
return cdn;
}
//- GA begin
int fitness(const Gene &p) { // 适应性
int cost = mcmf.minCost_Set(p.to_Set());
// printf("cost = %d\n", cost);
int Total = mcmf.networkNum * mcmf.costPerCDN;
if(cost == -1) return 1;
else return max(1, Total - cost);
}
// 返回一个选中基因的下标
int select(const vector<Gene> & genes) {
double R = Rand.Random_Real(0, 1);
double s = 0.0;
for(size_t i = 0; i < genes.size(); ++i) {
s += genes[i].P;
// printf("%f/%f\n", s, R);
if(s >= R) {
// printf("select %d\n", i);
return i;
}
}
return 0;
}
void GA(unordered_set<int> init = {}, int geneCnt = 20, double retain = 12, double crossP = 0.95, double mutationP = 0.25) { // 遗传算法
// 初始基因数,精英保留(geneCnt-retain),交叉率,变异率
int iterationCnt = 0;
int minCost = MCMF::INF;
vector<Gene> genes(geneCnt);
vector<Gene> next_genes(geneCnt);
priority_queue<Gene> que; // 最大堆选出最强的那20条染色体
unordered_set<int> initial;
if(init.empty()) initial = directConn();
else initial = move(init);
// 初始化基因
genes[0].set(initial, mcmf.networkNum);
for(int i = 1; i < geneCnt; ++i)
genes[i].reset(mcmf.networkNum);
while(runing && iterationCnt < 800) {
// for(int i = 0; i < geneCnt; ++i) {
// printf("基因型%d: ", i);
// genes[i].show();
// }
// 适应度计算
int sum = 0;
for(int i = 0; i < geneCnt; ++i) {
genes[i].fitness = fitness(genes[i]);
sum += genes[i].fitness;
minCost = min<double>(minCost, mcmf.networkNum * mcmf.costPerCDN - genes[i].fitness);
que.push(genes[i]); // 最大堆
}
for(int i = 0; i < geneCnt; ++i)
genes[i].P = genes[i].fitness*1.0 / sum;
next_genes.clear();
// 选择
for(int i = 0; i < geneCnt; ++i) {
if(que.size() > retain) next_genes[i] = que.top();
else next_genes[i] = genes[select(genes)];
que.pop();
}
for(int i = 0; i < geneCnt; ++i) // 复制
genes[i] = next_genes[i];
// XXOO
for(int i = 0; i < geneCnt; i+=2)
if(Rand.Random_Real(0, 1) < crossP)
genes[i] * genes[i+1];
// 突变
for(int i = 0; i < geneCnt; ++i)
if(Rand.Random_Real(0, 1) < mutationP)
genes[i].mutation();
++iterationCnt;
// printf("iterationCnt: %d minCost = %d\n", iterationCnt, minCost);
// break;
}
// mcmf.showSolution();
printf("iterationCnt=%d\n", iterationCnt);
// printf("minCost: %d/%d\n\n", minCost, mcmf.consumerNum * mcmf.costPerCDN);
mcmf.showRealMinCost();
}
//- GA end
//- 模拟退火 begin
int select(const vector<pair<int, double>> & cdn) {
double R = Rand.Random_Real(0, 1);
double s = 0.0;
for(size_t i = 0; i < cdn.size(); ++i) {
s += cdn[i].second;
// printf("%f/%f\n", s, R);
if(s >= R) {
// printf("select %d\n", i);
return i;
}
}
return 0;
}
unordered_set<int> SA(unordered_set<int>init = {}, int innerLoop = 10, double T = 20.0, double delta = 0.99999, double poi = 0.02) { // 模拟退火,初始温度,迭代系数,0.15的增点概率
// double T = 20.0, delta = 0.99999; // 初始温度20, 0.999-0.999999
unordered_set<int> backup, cur, best;
if(init.empty()) backup = directConn();
else backup = move(init);
int minCost = MCMF::INF, backCost = MCMF::INF, curCost = MCMF::INF;
backCost = mcmf.minCost_Set(backup);
minCost = min(minCost, backCost);
int iterationCnt = 0;
while(runing && T > 0.1) {
for(int loop = 0; loop < innerLoop && runing; ++loop) {
vector<pair<int, double>> cdn; // cdn选中的概率,概率越大,越容易被选中
double sum = 0.0;
int u = -1, v = -1;
// 随机选点u->v
for(auto x: backup)
sum += mcmf.nodes[x].evaluation;
for(auto x: backup)
cdn.push_back(make_pair(x, mcmf.nodes[x].evaluation / sum));
u = cdn[select(cdn)].first;
cdn.clear();
sum = 0.0;
for(size_t i = 0; i < mcmf.G[u].size(); ++i) {
int t = mcmf.edges[mcmf.G[u][i]].to;
if(t < mcmf.networkNum)
sum += 100000.0 / mcmf.nodes[t].evaluation;
// printf("%d %lf\n", t, mcmf.nodes[t].evaluation);
}
for(size_t i = 0; i < mcmf.G[u].size(); ++i) {
int t = mcmf.edges[mcmf.G[u][i]].to;
if(t < mcmf.networkNum)
cdn.push_back(make_pair(t, (100000.0 / mcmf.nodes[t].evaluation) / sum));
}
v = cdn[select(cdn)].first;
for(int x: backup) {
if(x == u) cur.insert(v);
else cur.insert(x);
}
if(Rand.Random_Real(0, 1) < poi)
cur.insert(Rand.Random_Int(0, mcmf.networkNum - 1)); // 增加一个点
curCost = mcmf.minCost_Set(cur);
if(curCost == -1) {// 无解
cur.clear();
continue;
}
else {
int dC = curCost - backCost;
// printf("dC: %d ratio: %lf probability: %lf\n", dC, curCost * 1.0 / minCost, exp(-dC / T));
if(min(1.0, exp(-dC / T)) > Rand.Random_Real(0, 1)) {// 接受
// printf("T: %lf dC: %d ratio: %lf\n", T, dC, curCost * 1.0 / minCost);
backup = move(cur);
backCost = curCost;
} else {
cur.clear();
}
if(minCost > backCost) {
minCost = backCost;
best = backup;
#ifdef _DEBUG
printf("T=%lf iterationCnt=%d\n", T, iterationCnt);
mcmf.showRealMinCost();
#endif
}
}
}
T *= delta;
++iterationCnt;
// printf("T=%lf iterationCnt=%d minCost = %d\n", T, iterationCnt, minCost);
}
#ifdef _DEBUG
printf("T=%lf iterationCnt=%d\n", T, iterationCnt);
mcmf.showRealMinCost();
#endif
// printf("Deploy CDN(%ld):\n", backup.size());
// for(int x: backup)
// printf("%d ", x);
// puts("\n=====Solution======");
// mcmf.showSolution();
return best;
}
//- 模拟退火 end
//- SAGA begin
void 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) { // 模拟退火,初始温度,迭代系数
// double T = 20.0, delta = 0.99999; // 初始温度20, 0.999-0.999999
unordered_set<int> initial;
vector<Gene> genes(geneCnt);
vector<Gene> next_genes(geneCnt);
if(init.empty()) initial = directConn();
else initial = move(init);
int minCost = MCMF::INF;
// for(int i = 0; i < geneCnt; ++i)
// genes[i].set(initial, mcmf.networkNum);
genes[0].set(initial, mcmf.networkNum);
unordered_set<int> direct = directConn();
for(int i = 1; i < geneCnt; ++i)
genes[i].reset(mcmf.networkNum);
int iterationCnt = 0;
// 忘记初始化了!导致段错误!!
Gene elite{mcmf.networkNum}; // 精英基因
while(runing && T > 0.1) {
next_genes.clear();
int fmin = MCMF::INF;
for(int idx = 0; runing && idx < geneCnt; ++idx) {
unordered_set<int> s = genes[idx].to_Set(); // 每条染色体
if(s.empty()) continue; // 空集的时候需要跳过
int fi = mcmf.minCost_Set(s), fj;
unordered_set<int> cur; // 邻域
// 计算领域
//- 随机选点u
int u = -1;
int i = Rand.Random_Int(0, s.size() - 1);
auto it = s.begin();
for(; it != s.end() && i; ++it, --i);
u = *it;
// - 选完了
// 随机选u->v
int v = -1;
do {
v = mcmf.edges[mcmf.G[u][Rand.Random_Int(0, mcmf.G[u].size() - 1)]].to; // (u, v)随机选点
} while(v >= mcmf.networkNum); // 防止移动到消费节点
// - 选完v了
for(int x: s) {
if(x == u) cur.insert(v);
else cur.insert(x);
}
if(Rand.Random_Real(0, 1) < poi)
cur.insert(Rand.Random_Int(0, mcmf.networkNum - 1)); // 增加一个点
// 邻域计算完毕
fj = mcmf.minCost_Set(cur);
if(fj != -1) {// 有解
int dC = fj - fi;
// printf("dC: %d\n", dC);
if(fi == -1 || min<double>(1, exp(-dC / T)) > Rand.Random_Real(0, 1)) {// 接受
genes[idx].set(cur, mcmf.networkNum);
genes[idx].fitness = fj;
if(fmin > fj) {
fmin = fj;
elite = genes[idx];
}
} else {
genes[idx].fitness = fi; // 不接收
if(fmin > fi) {
fmin = fi;
elite = genes[idx];
}
}
} else { // 无解,不接受
if(fmin > fi && fi != -1) {
fmin = fi;
elite = genes[idx];
}
genes[idx].fitness = (fi == -1?mcmf.networkNum * mcmf.costPerCDN:fi);
}
}
// 计算适应度
double sum = 0.0;
for(int idx = 0; runing && idx < geneCnt; ++idx) {
if(fmin == MCMF::INF) fmin = 0;
int dC = genes[idx].fitness - fmin;
genes[idx].fitness = exp(-dC / T);
sum += genes[idx].fitness;
}
for(int idx = 0; runing && idx < geneCnt; ++idx)
genes[idx].P = genes[idx].fitness / sum;
// 轮盘赌选择
next_genes[0] = elite; // 精英
for(int idx = 1; runing && idx < geneCnt; ++idx)
next_genes[idx] = genes[select(genes)];
for(int idx = 0; runing && idx < geneCnt; ++idx)
genes[idx] = next_genes[idx];
// 洗牌,打乱顺序,考虑是否必要
// random_shuffle(genes.begin(), genes.end());
// XXOO
for(int i = 0; runing && i < geneCnt; i+=2)
if(Rand.Random_Real(0, 1) < crossP)
genes[i] * genes[i+1];
// 突变
for(int i = 0; runing && i < geneCnt; ++i)
if(Rand.Random_Real(0, 1) < mutationP)
genes[i].mutation();
if(fmin != 0) minCost = min(minCost, fmin);
T *= delta;
++iterationCnt;
// printf("minCost: %d/%d\n\n", minCost, mcmf.consumerNum * mcmf.costPerCDN);
}
printf("T=%lf iterationCnt=%d\n", T, iterationCnt);
// mcmf.showSolution();
// printf("minCost: %d/%d\n\n", minCost, mcmf.consumerNum * mcmf.costPerCDN);
mcmf.showRealMinCost();
}
//- SAGA end
//- 禁忌搜索 begin
// 这块没写好,效果太差
unordered_set<int> Tabu(unordered_set<int>init = {}, int times = MCMF::INF) { // 禁忌搜索
typedef unordered_set<int> X;
list<int> H; // 禁忌表,队列
pair<int, X> x_best;
X x_now;
if(init.empty()) x_now = directConn();
else x_now = move(init);
pair<int, X> x_next{MCMF::INF, {}}; // 转移
H.push_back(x_best.first = mcmf.minCost_Set(x_now));
// for(int x: x_now)
// printf("%d ", x);
// puts("");
int iterationCnt = 0;
while(runing && iterationCnt < times) {
int Len = 0;
for(int u: x_now) {
for(size_t i = 0; i < mcmf.G[u].size() && runing; i+=2) {
++Len;
int v = mcmf.edges[mcmf.G[u][i]].to; // u->v
if(v < mcmf.networkNum) {
X tmp{}; // 邻居
for(int uu: x_now) {
if(uu != u) tmp.insert(uu);
else tmp.insert(v);
}
int cost = mcmf.minCost_Set(tmp);
if(cost == -1) continue;
if(find(H.begin(), H.end(), cost) == H.end() && cost < x_next.first) {
x_next.first = cost;
x_next.second = move(tmp);
if(x_best.first > cost) {
x_best.first = cost;
x_best.second = x_next.second;
}
}
}
}
}
H.push_back(x_next.first); // 入队
x_next.first = MCMF::INF;
x_now = move(x_next.second);
++iterationCnt;
while(H.size() > sqrt(Len)) H.pop_front();
}
printf("iterationCnt = %d\n", iterationCnt);
printf("minCost: %d/%d cdnNum: %ld\n\n", x_best.first, mcmf.consumerNum * mcmf.costPerCDN, x_best.second.size());
return x_best.second;
}
//- 禁忌搜索 end
//- BPSO begin
// 这个BPSO有坑,效果没想象中的好
double sig(double v, double Vmax, double Vmin) { // v->[0, 1]
return 1/(1+ pow((Vmax - v)/(v- Vmin), 2));
}
void BPSO(unordered_set<int> init = {}, int particleCnt = 10, double Vmin = 0.0, double Vmax = 10.0, double c1 = 1.0, double c2 = 1.0) {
vector<Particle> particles(particleCnt);
Particle pBest, gBest;
int fpBest = -1, fgBest = -1, fCur; // 当代最小费用,全局最小费用
vector<double> v[particleCnt]; // Vij
unordered_set<int> initial;
if(init.empty()) initial = directConn(); // 初始状态
else initial = move(init);
for(int i = 0; i < particleCnt; ++i) {
if(i) particles[i].reset(mcmf.networkNum);
else particles[i].set(initial, mcmf.networkNum); // 直连状态
for(int j = 0; j < mcmf.networkNum; ++j) // 初始化速度
v[i].push_back(Vmin + (Vmax - Vmin) * Rand.Random_Real(0, 1));
}
// for(int i = 0; i < particleCnt; ++i)
// for(int j = 0; j < mcmf.networkNum; ++j)
// printf("%lf\n", v[i][j]);
int iterationCnt = 0;
while(runing) {
for(int i = 0; i < particleCnt; ++i) {
if( (fCur = mcmf.minCost_Set(particles[i].to_Set())) != -1) {
if(fpBest == -1 || fpBest > fCur) {
fpBest = fCur;
pBest = particles[i];
}
if(fgBest == -1 || fgBest > fpBest) {
fgBest = fpBest;
gBest = pBest;
}
}
}
for(int i = 0; i < particleCnt; ++i) {
// puts("------------------------");
// printf("p[%d]: \n", i);
// particles[i].show();
for(int j = 0; j < mcmf.networkNum; ++j) {
v[i][j] = v[i][j] +
c1 * Rand.Random_Real(0, 1) * (pBest.getBit(j) - particles[i].getBit(j)) +
c2 * Rand.Random_Real(0, 1) * (gBest.getBit(j) - particles[i].getBit(j));
if(v[i][j] > Vmax) v[i][j] = Vmax;
else if(v[i][j] < Vmin) v[i][j] = Vmin;
// printf("sig(%lf) = %lf\n", v[i][j], sig(v[i][j], Vmax, Vmin));
if(Rand.Random_Real(0, 1) < sig(v[i][j], Vmax, Vmin)) particles[i].setBit(j, 1);
else particles[i].setBit(j, 0);
}
// particles[i].show();
}
fpBest = -1;
++iterationCnt;
// printf("iterationCnt = %d\n", iterationCnt);
// printf("minCost: %d/%d\n", fgBest, mcmf.consumerNum * mcmf.costPerCDN);
// break;
}
printf("iterationCnt = %d\n", iterationCnt);
printf("minCost: %d/%d\n", fgBest, mcmf.consumerNum * mcmf.costPerCDN);
}
//- BPSO end
void deploy_server(char * topo[MAX_EDGE_NUM], int line_num,char * filename)
{
Signal(SIGALRM, timeOutHandler);
// 启动计时器
alarm(86);
mcmf.loadGraph(topo, line_num);
if(mcmf.networkNum < 800){
mcmf.setCostCdnGap(80); // 不贪心降档
unordered_set<int> s = SA(XJBS(true), 1, 500, 0.9999, 0.00);
// mcmf.setCostCdnGap(1000); // 最后才贪心降档
// mcmf.minCost_Set(s);
// mcmf.showRealMinCost();
// GA(XJBS(true));
// SAGA(XJBS(true), 200, 0.00, 0.99, 20, 0.95, 0.05);
} else {
mcmf.setCostCdnGap(0); // 不贪心降档
unordered_set<int> s = SA(XJBS(true), 1, 500, 0.9999, 0.00);
mcmf.setCostCdnGap(1000); // 最后才贪心降档
mcmf.minCost_Set(s);
mcmf.showRealMinCost();
}
// SA(Tabu({}, 20));
// GA(XJBS(true));
// SAGA();
// BPSO(XJBS(true));
// XJBS();
// 初始解{},初始温度,增点概率,迭代系数,基因数,交叉率,变异率
// if(mcmf.networkNum < 200) {
// mcmf.setCostPerCdnMethod(false); // 动态变动
// SAGA(XJBS(), 2000, 0.00, 0.99, 30, 0.8, 0.05);
// }
// else if(mcmf.networkNum < 500) {
// mcmf.setCostPerCdnMethod(false); // 服务器费用固定
// SAGA(XJBS(false), 2000, 0.00, 0.99, 50, 0.8, 0.05);
// }
// else {
// mcmf.setCostPerCdnMethod(false); // 服务器费用固定
// SAGA(XJBS(true), 20, 0.00, 0.999, 6, 0.8, 0.05);
// }
// unordered_set<int> cdn{
// 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
// };
// mcmf.setCostCdnGap(1000);
// mcmf.minCost_Set(cdn);
// mcmf.showRealMinCost();
//- test
/*
double T = 20.0, delta = 0.99999, poi = 0.02;
double bestT = T, bestDelta = delta, bestPoi = poi;
int minCost = MCMF::INF;
int cost = 0;
// for(; T <= 100.0; T+=1) {
for(poi = 0.01; poi <= 1; poi += 0.01) {
alarm(88);
if( (cost = SA({}, T,delta, poi)) < minCost && cost != -1) {
minCost = cost;
bestT = T;
bestDelta = delta;
bestPoi = poi;
}
puts("--------------------");
printf("bestT = %lf/%lf bestDelta = %lf/%lf bestPoi = %lf/%lf minCost = %d\n", bestT, T, bestDelta, delta, bestPoi, poi, minCost);
puts("--------------------");
runing = true;
}
*/
//- test End
// 开始计算
write_result(mcmf.outputPath(), filename);
}
================================================
FILE: deploy.h
================================================
#ifndef __ROUTE_H__
#define __ROUTE_H__
#include "lib_io.h"
#include <signal.h>
#include <unistd.h>
#include <list>
#include <algorithm>
#include <cmath>
#include <queue>
#include <sys/types.h>
#include <sys/wait.h>
void deploy_server(char * graph[MAX_EDGE_NUM], int edge_num, char * filename);
#endif
================================================
FILE: gene.h
================================================
/*************************************************************************
> File Name: gene.cpp
> Author: Netcan
> Blog: http://www.netcan666.com
> Mail: 1469709759@qq.com
> Created Time: 2017-03-26 Sun 20:31:48 CST
************************************************************************/
#ifndef __GENE__
#define __GENE__
#include <cstdio>
#include <vector>
#include <algorithm>
#include <ctime>
#include <bitset>
#include <unordered_set>
#include "random.h"
using namespace std;
class Gene {
private:
int len; // 长度,0-1200
bitset<10000+5> code;
public:
double fitness; // 适应度/费用
double P; // 选中概率
Gene(): len(0), code(), fitness(0), P(0) {}
inline void reset(int len) { // 重置,亦即随机
this->len = len;
this->P = this->fitness = 0;
for(int i = 0; i < len; ++i)
code[i] = Rand.Random_Int(0, 1);
}
Gene(int len): len(len), fitness(0), P(0) {}
inline void operator*(Gene &b) { // 交叉,同时改变2条染色体
int end = Rand.Random_Int(1, len); // 交换的位置,交换一边就行了,因为另一边不动,这里交换两边
int begin = Rand.Random_Int(0, end - 1);
// printf("begin = %d end = %d len = %d\n", begin, end, len);
for(int i = begin; i < end; ++i)
if(code[i] != b.code[i]) {
code[i] = !code[i];
b.code[i] = !b.code[i];
}
}
inline void set(unordered_set<int> &s, int len) {
this->len = len;
std::vector<int> ss(s.begin(), s.end());
sort(ss.begin(), ss.end()); // 排序
size_t j = 0;
for(int i = 0; i < len && j < ss.size(); ++i) {
if(ss[j] == i) {
code[i] = 1;
++j;
} else // 忘记置0了
code[i] = 0;
}
}
inline bool operator<(const Gene &b) const { // 最小堆用
return this->fitness < b.fitness;
}
inline void operator=(const Gene &b) { // 赋值
this->len = b.len;
this->fitness = b.fitness;
this->P = b.P;
code = b.code;
}
inline bool operator==(const Gene &b)const { // 判断序列是否相等
return code == b.code;
}
inline void mutation(int loc = -1) { // 突变,[0, len)
if(loc == -1) loc = Rand.Random_Int(0, len - 1);
else if(loc >= len) return;
// printf("loc = %d\n", loc);
code[loc] = !code[loc];
}
inline void show() const {
for(int i = 0; i < len; ++i) {
if(i != 0 && i % 8 == 0) printf(",");
printf(code[i]?"1":"0");
}
puts("");
}
inline unordered_set<int> to_Set() const {
unordered_set<int> S;
for(int i = 0; i < len; ++i)
if(code[i]) S.insert(i);
return S;
}
inline bool getBit(int loc) {
return code[loc];
}
inline void setBit(int loc, bool x) {
code[loc] = x;
}
};
typedef Gene Particle;
#endif
// int main(void) {
// Gene ga(10);
// Gene gb(10);
// ga.show();
// gb.show();
// ga * gb;
// ga.show();
// gb.show();
// ga.show();
// ga.mutation();
// ga.show();
// for(auto x: ga.to_Set()) {
// printf("%d\n", x);
// }
// return 0;
// }
================================================
FILE: io.cpp
================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include <sys/timeb.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#define MAX_LINE_LEN 55000
#define INLINE static __inline
#ifdef _DEBUG
#define PRINT printf
#else
#define PRINT(...)
#endif
INLINE void write_file(const bool cover, const char * const buff, const char * const filename);
void print_time(const char *head)
{
#ifdef _DEBUG
struct timeb rawtime;
struct tm * timeinfo;
ftime(&rawtime);
timeinfo = localtime(&rawtime.time);
static int ms = rawtime.millitm;
static unsigned long s = rawtime.time;
int out_ms = rawtime.millitm - ms;
unsigned long out_s = rawtime.time - s;
ms = rawtime.millitm;
s = rawtime.time;
if (out_ms < 0)
{
out_ms += 1000;
out_s -= 1;
}
printf("%s date/time is: %s \tused time is %lu s %d ms.\n", head, asctime(timeinfo), out_s, out_ms);
#endif
}
int read_file(char ** const buff, const unsigned int spec, const char * const filename)
{
FILE *fp = fopen(filename, "r");
if (fp == NULL)
{
PRINT("Fail to open file %s, %s.\n", filename, strerror(errno));
return 0;
}
PRINT("Open file %s OK.\n", filename);
char line[MAX_LINE_LEN + 2];
unsigned int cnt = 0;
while ((cnt < spec) && !feof(fp))
{
line[0] = 0;
if (fgets(line, MAX_LINE_LEN + 2, fp) == NULL) continue;
if (line[0] == 0) continue;
buff[cnt] = (char *)malloc(MAX_LINE_LEN + 2);
strncpy(buff[cnt], line, MAX_LINE_LEN + 2 - 1);
buff[cnt][MAX_LINE_LEN + 1] = 0;
cnt++;
}
fclose(fp);
PRINT("There are %d lines in file %s.\n", cnt, filename);
return cnt;
}
void write_result(const char * const buff,const char * const filename)
{
// 以覆盖的方式写入
write_file(1, buff, filename);
}
void release_buff(char ** const buff, const int valid_item_num)
{
for (int i = 0; i < valid_item_num; i++)
free(buff[i]);
}
INLINE void write_file(const bool cover, const char * const buff, const char * const filename)
{
if (buff == NULL)
return;
const char *write_type = cover ? "w" : "a";//1:覆盖写文件,0:追加写文件
FILE *fp = fopen(filename, write_type);
if (fp == NULL)
{
PRINT("Fail to open file %s, %s.\n", filename, strerror(errno));
return;
}
PRINT("Open file %s OK.\n", filename);
fputs(buff, fp);
fputs("\n", fp);
fclose(fp);
}
================================================
FILE: lib/lib_io.h
================================================
#ifndef __LIB_IO_H__
#define __LIB_IO_H__
#define MAX_EDGE_NUM (2000 * 20)
//读取文件并按行输出到buff。
//buff为一个指针数组,每一个元素是一个字符指针,对应文件中一行的内容。
//spec为允许解析的最大行数。
extern int read_file(char ** const buff, const unsigned int spec, const char * const filename);
//将result缓冲区中的内容写入文件,写入方式为覆盖写入
extern void write_result(const char * const buff,const char * const filename);
//释放读文件的缓冲区
extern void release_buff(char ** const buff, const int valid_item_num);
#endif
================================================
FILE: lib/lib_time.h
================================================
#ifndef __LIB_TIME_H__
#define __LIB_TIME_H__
//打印时间。入参为打印信息头
void print_time(const char * const head);
#endif
================================================
FILE: mcmf.cpp
================================================
/*************************************************************************
> File Name: spfa.cpp
> Author: Netcan
> Blog: http://www.netcan666.com
> Mail: 1469709759@qq.com
> Created Time: 2017-03-21 Tue 21:25:20 CST
************************************************************************/
#include "mcmf.h"
char MCMF::topo[50000*1000*6];
void MCMF::getPath(int cost) {
if(cost != -1 && cost < solutionPath.first) {
solutionPath.first = cost;
solutionPath.second.clear(); // 记得清理
vector<int> tmpPath;
memset(vis, 0, sizeof(vis[0]) * Vn);
findPath(tmpPath, superSource, INF, INF);
}
}
int MCMF::findPath(vector<int> & tmpPath, int u, int minFlow, int totalFlow) { // dfs,深搜路径,路径上的最小流量,总流量
if(vis[u]) return 0;
else if(isConsumer(u)) { // 到达消费节点,找到一条路径
solutionPath.second.push_back(tmpPath);
vector<int> &b = solutionPath.second.back();
b.push_back(u - networkNum); // 转换为消费节点的id
b.push_back(minFlow);
b.push_back(servers[nodes[b.front()].bestCdnId].level); // 档次
return minFlow;
}
vis[u] = true;
if(u < superSource) tmpPath.push_back(u);
int tf = totalFlow;
for(size_t i = 0; i < G[u].size(); ++i) {
Edge &e = edges[G[u][i]];
if(e.flow > 0) { // 流过的流量>0
// printf("%d->%d flow: %d\n", e.from, e.to, e.flow);
int v = e.to;
if(!vis [v]) {
if(totalFlow > 0) {
int t = findPath(tmpPath, v,
min(minFlow, min(totalFlow, e.flow)),
min(totalFlow, e.flow));
e.flow -= t;
totalFlow -= t;
}
else break;
}
}
}
vis[u] = false;
if(u < superSource) tmpPath.pop_back();
return tf;
}
int MCMF::aug(int u, int minFlow, int &tmpCost, int &cost) {
if(u == superSink) { // 到达终点
cost += tmpCost * minFlow;
return minFlow;
}
vis[u] = true;
int tf = minFlow;
for(size_t i = 0; i < G[u].size(); ++i) {
Edge &e = edges[G[u][i]];
if( (e.cap - e.flow) && !e.cost && !vis[e.to]) {
int d = aug(e.to, min(tf, (e.cap - e.flow)), tmpCost, cost);
e.flow += d;
edges[G[u][i] ^ 1].flow -= d;
tf -= d;
if(! tf) return minFlow;
}
}
return minFlow - tf;
}
bool MCMF::modLabel(int &tmpCost) {
int d = INF;
for(int u=0; u < Vn; ++u) // 遍历完全部节点
if(vis[u]) {
for(size_t i = 0; i < G[u].size(); ++i) {
Edge &e = edges[G[u][i]];
if( (e.cap - e.flow) && !vis[e.to] && e.cost < d)
d = e.cost;
}
}
if(d == INF) return false;
for(int u=0; u < Vn; ++u)
if(vis[u]) {
for(size_t i = 0; i < G[u].size(); ++i) {
edges[G[u][i]].cost -= d;
edges[G[u][i] ^ 1].cost += d;
}
}
tmpCost += d;
return true;
// SLF优化
/*
memset(d, 0x3f, sizeof(int) * Vn);
d[superSink] = 0;
static deque<int> que; que.push_back(superSink);
while(que.size())
{
int dt, u = que.front(); que.pop_front();
for(size_t i = 0; i < G[u].size(); ++i) {
Edge &e = edges[G[u][i]], &re = edges[G[u][i] ^ 1];
if( (re.cap - re.flow) && (dt = d[u] - e.cost) < d[e.to] )
(d[e.to] = dt) <= d[que.size() ? que.front() : 0]
? que.push_front(e.to) : que.push_back(e.to);
}
}
for(int u=0; u<=superSink; ++u)
for(size_t i = 0; i < G[u].size(); ++i) {
Edge &e = edges[G[u][i]];
e.cost += d[e.to] - d[u];
}
tmpCost += d[superSource];
return d[superSource] < INF;
*/
}
void MCMF::AddEdge(int from, int to, int cap, int cost) {
edges.push_back(Edge(to, cap, 0, cost));
edges.push_back(Edge(from, 0, 0, -cost));
int m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
if(from < networkNum) {
if(isConsumer(to)) // 网络节点直连消费节点,计算需要的总共流量
needFlow += cap;
if(to < superSource)
nodes[from].nodeFlow += cap;
}
}
void MCMF::showSolution() const{
int totalFlow = 0;
for(const auto &x : solutionPath.second) {
for(vector<int>::const_iterator i = x.begin(); i != x.end() - 1; ++i) {
if(i == x.begin()) printf("%d", *i);
else printf("->%d", *i);
}
totalFlow += x.back();
printf(" flow: %d\n", x.back());
}
printf("Flow :%d/%d Cost: %d/%d\n", totalFlow, needFlow, solutionPath.first, costPerCDN * consumerNum);
}
void MCMF::loadGraph(char * topo[MAX_EDGE_NUM], int line_num) {
sscanf(topo[0], "%d%d%d", &networkNum, &edgeNum, &consumerNum); // 网络节点数量 网络链路数量 消费节点数量
// solutionPath.first = consumerNum * costPerCDN; // 待求
superSource = consumerNum + networkNum; // 超级源点、汇点
superSink = consumerNum + networkNum + 1;
Vn = superSink + 1;
int a, b, c, d, maxCap = 0;
int i;
for(i = 2; i < line_num && !isspace(topo[i][0]); ++i) {
sscanf(topo[i], "%d%d%d", &a, &b, &c); // 服务器硬件档次ID 输出能力 硬件成本
servers.push_back(Server(a, b, c));
// printf("level: %d outFlow: %d cost: %d\n", a, b, c);
}
// printf("maxFlowServer level: %d outFlow: %d cost: %d\n", maxFlowServer.level, maxFlowServer.outFlow, maxFlowServer.cost);
for(++i; i < line_num && !isspace(topo[i][0]); ++i) {
sscanf(topo[i], "%d%d", &a, &b); // 网络节点ID 部署成本
nodes[a].deployCost = b;
// printf("node: %d cost: %d\n", a, b);
}
for(++i; i < line_num && !isspace(topo[i][0]); ++i) {
sscanf(topo[i], "%d%d%d%d", &a, &b, &c, &d); // 链路起始节点ID 链路终止节点ID 总带宽大小 单位网络租用费
AddEdge(a, b, c, d);
AddEdge(b, a, c, d);
// printf("u: %d v: %d bandwidth: %d cost: %d\n", a, b, c, d);
}
for(++i; i < line_num; ++i) {
sscanf(topo[i], "%d%d%d", &a, &b, &c); // 消费节点ID 相连网络节点ID 视频带宽消耗需求
AddEdge(b, a + networkNum, c, 0); // 与网络节点相连
AddEdge(a + networkNum, superSink, c, 0); // 与汇点相连
maxCap = max(maxCap, c);
// printf("consumer: %d connect: %d need: %d\n", a, b, c);
// vector<int> path{to, from, bandwidth}; // 直连策略
// solutionPath.second.push_back(move(path));
}
sort(servers.begin(), servers.end());
maxFlowServer = servers.back();
// vector<Server>::iterator it;
// if( (it = lower_bound(servers.begin(), servers.end(), maxCap)) != servers.end()) // >= 最大档
// maxFlowServer = *it; // 存放下标,nodes输出路径的时候用
// else maxFlowServer = servers.back(); // 最大的level
// printf("l: %d\n", maxFlowServer.level);
costPerCDN = maxFlowServer.cost; // 以最大档次的费用为准
edgeNum = edges.size(); // 边数
solutionPath.first = INF;
calcEvaluation();
}
const char* MCMF::outputPath() {
// getPath(solutionPath.first, true); // 放到最后才遍历路径,提高性能
// showRealMinCost();
char buffer[10];
char *pt = topo, *pb = buffer;
snprintf(buffer, sizeof(buffer), "%ld\n\n", solutionPath.second.size());
while(*pb && (*pt++ = *pb++));
for(auto &x: solutionPath.second) {
for(auto it = x.begin(); it != x.end(); ++it) {
snprintf(buffer, sizeof(buffer), it == x.begin() ? "%d":" %d", *it);
pb = buffer;
while(*pb && (*pt++ = *pb++));
}
*pt++ = '\n';
}
*--pt = 0;
return topo;
}
MCMF mcmf;
================================================
FILE: mcmf.h
================================================
/*************************************************************************
> File Name: spfa.h
> Author: Netcan
> Blog: http://www.netcan666.com
> Mail: 1469709759@qq.com
> Created Time: 2017-03-22 Wed 12:33:02 CST
************************************************************************/
#ifndef __MCMF__
#define __MCMF__
#include <cstdio>
#include <assert.h>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <cstdlib>
#include <deque>
#include <vector>
#include <unordered_set>
#include <unordered_map>
#include "deploy.h"
using namespace std;
extern bool runing;
class MCMF{
private:
struct Edge{
int to, cap, flow ,cost, oldCost;
Edge() {}
Edge(int to, int cap, int flow, int cost): to(to), cap(cap), flow(flow), cost(cost), oldCost(cost) {}
};
struct Server {
int level, outFlow, cost;
Server(int level, int outFlow, int cost): level(level), outFlow(outFlow), cost(cost) {}
Server() {
level = outFlow = cost = 0;
}
bool operator<(const Server &b) const {
if(this->outFlow != b.outFlow) return this->outFlow < b.outFlow;
else return this->cost < b.cost;
}
bool operator<(int flow) const {
return this->outFlow < flow;
}
};
static const int N = 20000+5;
static char topo[50000*1000*6]; // 网络路径数量不得超过300000条, 单条路径的节点数量不得超过10000个, 所有数值必须为大于等于0的整数,数值大小不得超过1000000。
int Vn, superSource, superSink; // 总节点数,超级源点/汇点,需要的流量
size_t minCostCdnGap = 50; // 当cdn小于这个数的时候,进行贪心降档
int d[N];
bool vis[N]; // 标记数组
vector<Server> servers; // 服务器
Server maxFlowServer;
#ifdef _DEBUG
int realMinCost = INF; // 保存真实的最小费用,最后打印,调试用
#endif
pair<int, vector<vector<int>>> solutionPath; // 当前可行解,路径
// ZKW算法
int aug(int u, int minFlow, int &tmpCost, int &cost);
bool modLabel(int &tmpCost);
inline void reset() { // 还原初始状态,删除源点
for(size_t i = 0; i < G[superSource].size(); ++i)
G[edges[G[superSource][i]].to].pop_back(); // 删除链接超源的边
for(int i=G[superSource].size() * 2; i > 0; --i) edges.pop_back(); // 删除超源的边
for(size_t i = 0; i < edges.size(); ++i) {
edges[i].cost = edges[i].oldCost;
edges[i].flow = 0; // 重置流量
}
G[superSource].clear();
}
inline void calcEvaluation() { // 评估函数,评估值越小越好
for(int u = 0; u < networkNum; ++u)
nodes[u].evaluation = nodes[u].deployCost * 100 / nodes[u].nodeFlow;
}
int findPath(vector<int> & tmpPath, int u, int minFlow, int totalFlow);
void getPath(int cost);
inline int pathFlowCost() { // 路径流量费
int cost = 0, flow = 0;
int tmpCost = 0;
do {
int f;
do {
memset(vis, 0, sizeof(vis[0]) * Vn);
f = aug(superSource, INF, tmpCost, cost);
flow += f;
}
while(f);
}
while(modLabel(tmpCost));
if(flow < needFlow) return -1;
return cost;
// SLF优化
/*
while(modLabel(tmpCost))
do bzero(vis, sizeof(vis));
while(aug(superSource, INF, tmpCost, cost));
*/
}
inline int minCost(const unordered_set<int> &cdn) { // 调用setCDN后再调用minCost!! 注意不能连续调用多次minCost!!!
int cost = pathFlowCost(), cdnCost = 0, cdnFlow = 0, minCdnFlowCost = INF;
if(cost == -1) return -1;
vector<pair<int, int>> diff; // 存放差/节点名
unordered_map<int, int> eId; // 存放超源到cdn的边的下标
bool downShift = false;
if(cdn.size() < minCostCdnGap) downShift = true;
for (size_t i = 0; i < G[superSource].size(); i++) { // 降档
Edge &e = edges[G[superSource][i]];
if(e.flow == 0) continue;
vector<Server>::iterator it;
if( (it = lower_bound(servers.begin(), servers.end(), e.flow)) != servers.end()) // >= 降档
nodes[e.to].bestCdnId = it - servers.begin(); // 存放下标,nodes输出路径的时候用
else nodes[e.to].bestCdnId = servers.size() - 1; // 最大的level
if(downShift) {
eId[e.to] = G[superSource][i];
e.cap = servers[nodes[e.to].bestCdnId].outFlow;
cdnFlow += servers[nodes[e.to].bestCdnId].outFlow; // 计算总费用
}
cdnCost += servers[nodes[e.to].bestCdnId].cost; // 计算总费用
// printf("%d e.flow: %d/%d(%d)\n", e.to, e.flow, servers[nodes[e.to].bestCdnId].outFlow, servers[nodes[e.to].bestCdnId].level);
}
minCdnFlowCost = min(minCdnFlowCost, cost + cdnCost); // 更新总费用
// printf("minCdnFlowCost %d\n", minCdnFlowCost);
if(downShift) {
bool exit = false;
while(! exit) {
diff.clear();
for (size_t i = 0; i < G[superSource].size(); i++) {
const Edge &e = edges[G[superSource][i]];
if(e.flow == 0) continue;
// 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);
if(nodes[e.to].bestCdnId == 0) diff.push_back(make_pair(0, e.to));
else if(e.flow == servers[nodes[e.to].bestCdnId - 1].outFlow) { // 直接可以降档
diff.push_back(make_pair(INF, e.to));
}
else diff.push_back(make_pair(
(servers[nodes[e.to].bestCdnId].cost - servers[nodes[e.to].bestCdnId - 1].cost) /
(e.flow - servers[nodes[e.to].bestCdnId - 1].outFlow)
, e.to));
}
sort(diff.begin(), diff.end(), greater<pair<int, int>>());
for(size_t i = 0; i < diff.size(); ++i) {
int u = diff[i].second;
if(nodes[u].bestCdnId == 0) continue;
for(size_t j = 0; j < edges.size(); ++j) {
edges[j].cost = edges[j].oldCost;
edges[j].flow = 0; // 重置流量
}
int dc = servers[nodes[u].bestCdnId].cost - servers[nodes[u].bestCdnId - 1].cost;
int df = servers[nodes[u].bestCdnId].outFlow - servers[nodes[u].bestCdnId - 1].outFlow;
if(cdnFlow - df >= needFlow) { // 预判
cdnCost -= dc; // 更新Cdn费用
cdnFlow -= df;
edges[eId[u]].cap = servers[nodes[u].bestCdnId - 1].outFlow;
--nodes[u].bestCdnId;
cost = pathFlowCost();
if(cost == -1 || cost + cdnCost > minCdnFlowCost) { // 降档失败
cdnCost += dc;
cdnFlow += df;
edges[eId[u]].cap = servers[nodes[u].bestCdnId + 1].outFlow;
++nodes[u].bestCdnId;
if(cost == -1){
exit = true;
break;
}
} else {// 降档成功,有解
minCdnFlowCost = cost + cdnCost;
break;
// printf("success: %d\n", u);
}
} else {
exit = true;
break;
}
}
// printf("minCdnFlowCost %d\n", minCdnFlowCost);
// printf("%d diff: %d\n", u, diff[i].first);
// printf("cdnFlow: %d cdnCost: %d needFlow: %d minCdnFlowCost: %d\n", cdnFlow, cdnCost, needFlow, minCdnFlowCost);
}
}
cost = minCdnFlowCost;
// 计算部署费用
#ifdef _DEBUG
int realCost = cost;
#endif
for(auto c: cdn) {
cost += nodes[c].deployCost;
#ifdef _DEBUG
realCost += nodes[c].deployCost;
#endif
}
#ifdef _DEBUG
realMinCost = min(realMinCost, realCost);
#endif
if(cost < solutionPath.first) {
if(downShift) {
for(size_t j = 0; j < edges.size(); ++j) {
edges[j].cost = edges[j].oldCost;
edges[j].flow = 0; // 重置流量
}
pathFlowCost();
}
// 打印档次
/*
vector<pair<int,int>> v;
for (size_t i = 0; i < G[superSource].size(); i++) { // 降档
Edge &e = edges[G[superSource][i]];
v.push_back(make_pair(e.to, G[superSource][i]));
}
sort(v.begin(), v.end());
for(size_t i = 0; i < v.size(); ++i) {
Edge &e = edges[v[i].second];
// printf("%d e.flow: %d/%d(%d)\n", e.to, e.flow, servers[nodes[e.to].bestCdnId].outFlow, servers[nodes[e.to].bestCdnId].level);
printf("%d\t%d\n", e.to, servers[nodes[e.to].bestCdnId].level);
}
*/
getPath(cost); // 更新方案
}
return cost;
}
inline void setCdn(const unordered_set<int> & cdn) {
reset();
for(int x: cdn)
AddEdge(superSource, x, maxFlowServer.outFlow, 0);
}
public:
struct Node{
int deployCost; // 节点部署费用
int nodeFlow; // 每个节点的流量
int bestCdnId; // 存放每个节点最适合的服务器档次(下标)
double evaluation; // 每个节点的评估值
Node() {
deployCost = bestCdnId = nodeFlow = evaluation = 0;
}
} nodes[10000 + 5];
vector<int> G[N]; // 图
vector<Edge> edges; // 边集
int networkNum, edgeNum, consumerNum, needFlow, costPerCDN = 0;
static const int INF = 0x3f3f3f3f;
friend class MCMF_SCALING;
void inline showRealMinCost() {
#ifdef _DEBUG
printf("\x1B[31mReal minCost: %d/%d\x1B[0m\n", realMinCost, consumerNum * costPerCDN);
#endif
}
inline bool isConsumer(int u) {
return u >= networkNum && u < superSource;
}
MCMF() {
needFlow = 0;
};
inline void setCostCdnGap(int x) {
minCostCdnGap = x;
}
void AddEdge(int from, int to, int cap, int cost);
void showSolution() const;
void loadGraph(char * topo[MAX_EDGE_NUM], int line_num);
const char* outputPath();
inline int minCost_Set(const unordered_set<int> &cdn) {
setCdn(cdn);
return minCost(cdn);
}
};
extern MCMF mcmf;
#endif
================================================
FILE: random.h
================================================
/*************************************************************************
> File Name: random.cpp
> Author: Netcan
> Blog: http://www.netcan666.com
> Mail: 1469709759@qq.com
> Created Time: 2017-03-27 Mon 07:40:54 CST
************************************************************************/
#ifndef __RANDOM__
#define __RANDOM__
#include <cstdio>
#include <random>
class Random {
private:
std::default_random_engine generator;
public:
// Random(time_t t = time(NULL)): generator(t) {}
inline uint32_t Random_Int(uint32_t min, uint32_t max) { // [min, max]
return std::uniform_int_distribution<uint32_t>{min, max}(generator);
}
inline double Random_Real(double min, double max) { // [min, max)
return std::uniform_real_distribution<double>{min, max}(generator);
}
};
Random Rand;
#endif
================================================
FILE: testBranch.txt
================================================
hello world
netcan
gitextract_mkuby_3i/ ├── .gitignore ├── CMakeLists.txt ├── README.md ├── cdn.cpp ├── deploy.cpp ├── deploy.h ├── gene.h ├── io.cpp ├── lib/ │ ├── lib_io.h │ └── lib_time.h ├── mcmf.cpp ├── mcmf.h ├── random.h ├── testBranch.txt └── 初赛样例参数分析.xlsx
SYMBOL INDEX (39 symbols across 6 files)
FILE: cdn.cpp
function main (line 6) | int main(int argc, char *argv[])
FILE: deploy.cpp
function sigFunc (line 10) | sigFunc *
function timeOutHandler (line 22) | void timeOutHandler(int signo) {
function directConn (line 28) | unordered_set<int> directConn() {
function cmp (line 37) | bool cmp(int u1, int u2) { // 比较函数,消费降低需要的流量越低,排在越前
function XJBS (line 54) | unordered_set<int> XJBS(bool sorted = false) {
function evaluationSelect (line 112) | unordered_set<int> evaluationSelect() {
function fitness (line 129) | int fitness(const Gene &p) { // 适应性
function select (line 138) | int select(const vector<Gene> & genes) {
function GA (line 152) | void GA(unordered_set<int> init = {}, int geneCnt = 20, double retain = ...
function select (line 228) | int select(const vector<pair<int, double>> & cdn) {
function SA (line 241) | unordered_set<int> SA(unordered_set<int>init = {}, int innerLoop = 10, d...
function SAGA (line 338) | void SAGA(unordered_set<int>init = {}, double T = 20.0, double poi = 0.0...
function Tabu (line 474) | unordered_set<int> Tabu(unordered_set<int>init = {}, int times = MCMF::I...
function sig (line 533) | double sig(double v, double Vmax, double Vmin) { // v->[0, 1]
function BPSO (line 537) | void BPSO(unordered_set<int> init = {}, int particleCnt = 10, double Vmi...
function deploy_server (line 606) | void deploy_server(char * topo[MAX_EDGE_NUM], int line_num,char * filename)
FILE: gene.h
function class (line 20) | class Gene {
function set (line 48) | inline void set(unordered_set<int> &s, int len) {
function operator (line 62) | inline bool operator<(const Gene &b) const { // 最小堆用
function operator (line 72) | inline bool operator==(const Gene &b)const { // 判断序列是否相等
function getBit (line 97) | inline bool getBit(int loc) {
function setBit (line 100) | inline void setBit(int loc, bool x) {
type Gene (line 105) | typedef Gene Particle;
FILE: io.cpp
function print_time (line 24) | void print_time(const char *head)
function read_file (line 48) | int read_file(char ** const buff, const unsigned int spec, const char * ...
function write_result (line 76) | void write_result(const char * const buff,const char * const filename)
function release_buff (line 83) | void release_buff(char ** const buff, const int valid_item_num)
function INLINE (line 89) | INLINE void write_file(const bool cover, const char * const buff, const ...
FILE: mcmf.h
function class (line 27) | class MCMF{
function reset (line 68) | inline void reset() { // 还原初始状态,删除源点
function calcEvaluation (line 78) | inline void calcEvaluation() { // 评估函数,评估值越小越好
function pathFlowCost (line 85) | inline int pathFlowCost() { // 路径流量费
function minCost (line 109) | inline int minCost(const unordered_set<int> &cdn) { // 调用setCDN后再调用minCo...
function setCdn (line 251) | inline void setCdn(const unordered_set<int> & cdn) {
function isConsumer (line 279) | inline bool isConsumer(int u) {
function setCostCdnGap (line 287) | inline void setCostCdnGap(int x) {
FILE: random.h
function class (line 14) | class Random {
function Random_Real (line 23) | inline double Random_Real(double min, double max) { // [min, max)
Condensed preview — 15 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (50K chars).
[
{
"path": ".gitignore",
"chars": 34,
"preview": "/spfa\n/gene\n/random\n/mcmf_scaling\n"
},
{
"path": "CMakeLists.txt",
"chars": 597,
"preview": "# CMake 最低版本号要求\ncmake_minimum_required(VERSION 2.8)\n\n# 项目信息\nproject(cdn)\n\n# include路径\ninclude_directories(${PROJECT_SOUR"
},
{
"path": "README.md",
"chars": 188,
"preview": "## 心路历程\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%"
},
{
"path": "cdn.cpp",
"chars": 587,
"preview": "#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 "
},
{
"path": "deploy.cpp",
"chars": 18277,
"preview": "#include \"deploy.h\"\n#include <stdio.h>\n#include \"random.h\"\n#include \"mcmf.h\"\n#include \"gene.h\"\n\ntypedef void (sigFunc)(i"
},
{
"path": "deploy.h",
"chars": 307,
"preview": "#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#in"
},
{
"path": "gene.h",
"chars": 2819,
"preview": "/*************************************************************************\n\t> File Name: gene.cpp\n\t > Author: Netcan\n\t "
},
{
"path": "io.cpp",
"chars": 2499,
"preview": "#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"
},
{
"path": "lib/lib_io.h",
"chars": 456,
"preview": "#ifndef __LIB_IO_H__\n#define __LIB_IO_H__\n\n#define MAX_EDGE_NUM (2000 * 20)\n\n//读取文件并按行输出到buff。\n//buff为一个指针数组,每一个元素是一个"
},
{
"path": "lib/lib_time.h",
"chars": 113,
"preview": "#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",
"chars": 6547,
"preview": "/*************************************************************************\n > File Name: spfa.cpp\n > Author: Netcan\n "
},
{
"path": "mcmf.h",
"chars": 8713,
"preview": "/*************************************************************************\n\t> File Name: spfa.h\n\t > Author: Netcan\n\t >"
},
{
"path": "random.h",
"chars": 826,
"preview": "/*************************************************************************\n\t> File Name: random.cpp\n\t > Author: Netcan\n"
},
{
"path": "testBranch.txt",
"chars": 20,
"preview": "hello world\nnetcan\n\n"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the netcan/2017-HUAWEI-Codecraft GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 15 files (41.0 KB), approximately 15.5k tokens, and a symbol index with 39 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.