2017华为软挑---SPFA、ZKW、模拟退火
来源:互联网 发布:淘宝上男装剪标折扣店 编辑:程序博客网 时间:2024/05/17 09:34
环境:CentOS 6.7
————————核心———————
deploy.h
#ifndef __ROUTE_H__#define __ROUTE_H__#include "lib_io.h"#include "lib_time.h"#include "string.h"#include "stdlib.h"#include "time.h"//#include <sys/time.h>#include "iostream"#include "fstream"#include "vector"#include "queue"#include "algorithm"#include "map"#include "set"#include "sstream"using namespace std;void deploy_server(char * graph[MAX_EDGE_NUM], int edge_num, char * filename);#define INF 2000000000#define INT_MAX 2000000000#define INT_MAX1 2000000000#define MAX_netNodeCnt 1002 // 网络节点最大数+2#define MAX_consumeNodeCnt 500 // 消费节点最大数#define MAX_linkeCnt 20000 // 链路最大数struct Edge{ //int from; // 链路起始节点ID int to; // 链路终止节点ID int cap; // 总带宽 int cost; // 单位带宽租用费 int flow; int next;};// 消费节点信息struct ConsumeNode{ int ID; // 消费节点ID int netID; // 相连网络节点ID int demand; // 视频带宽需求};// 用于结果输出struct Result{ vector<int> path; // 路径 int flow; // 占用带宽 Result() { path.clear(); flow = 0; }};struct Node{ int id; // 网络节点ID int degree; // 度 Node() { id = 0; degree = 0; } bool operator < (const struct Node &node)const { return degree > node.degree; }};void build(char * topo[MAX_EDGE_NUM], int line_num);void addEdge(int from, int to, int cap, int cost, int &id);bool min_cost(int &cost, int nEdge, int nServer); // 最小费用流void record_result();void dfs(int u, Result &r, int &flow); // 搜索路径 bool min_cost1(); void record_result1();///////////////////////随机算法/////////////////////////////// 个体class Entity{public: set<int> position; // 服务器安放的位置 int fitness; // 适应度值,即总的花费 Entity() { fitness = INT_MAX; position.clear(); } bool operator < (const Entity &e) const { return fitness < e.fitness; } int getFit(); int getFit1();};void init(); // 种群初始化 void mutate(); // 变异函数void mainEA(); // 随机算法主函数#endif
deploy.cpp
#include "deploy.h"#include "algorithm"#include <stdio.h>int netNodeCnt; // 网络节点数量int linkeCnt; // 网络链路数量int consumeNodeCnt; // 消费节点数量int serverCost; // 视频内容服务器部署成本ConsumeNode consume[MAX_consumeNodeCnt]; // 消费节点信息数组Edge edge[4*MAX_linkeCnt]; // 链路信息数组int head[MAX_netNodeCnt]; int preV[MAX_netNodeCnt]; int preE[MAX_netNodeCnt];int dist[MAX_netNodeCnt];bool vis[MAX_netNodeCnt];int id = 0; // 边的IDint S, T; // 超级源点、汇点int F; // 总带宽需求int minCost = INT_MAX; // 最小花费map<int, int> mapConsume; // 记录网络节点与那个消费节点相连vector<Result> path; // 路径vector<Result> bestPath; // 最佳路径string result; Entity Best; // 最优解个体double PMUTATION1 = 55;double PMUTATION2 = 90;int POPSIZE = 50;set<int> sChoice; // 服务器选择范围vector<int> vChoice;set<int> bad; // 禁忌表int maxflow;int serverNum;int cur[MAX_netNodeCnt], pre[MAX_netNodeCnt];clock_t start, finish;Node node[MAX_netNodeCnt];//struct timeval T1, T2, T3; double decs = 0.97;double temp = 150;double thold = 15;Entity MostBest;void solve();//You need to complete the function void deploy_server(char * topo[MAX_EDGE_NUM], int line_num, char * filename){ //gettimeofday(&T1, NULL); build(topo, line_num); srand(time(NULL)); //gettimeofday(&T2, NULL); mainEA(); cout << "minCost:" << minCost << endl; record_result(); //write_result(result.c_str(), filename);}void addEdge(int from, int to, int cap, int cost, int &id){ edge[id].to = to; edge[id].cap = cap; edge[id].cost = cost; edge[id].flow = 0; edge[id].next = head[from]; head[from] = id++;}// 读入文件,建图void build(char * topo[MAX_EDGE_NUM], int line_num){ memset(head, -1, sizeof(head)); istringstream sin; sin.str(topo[0]); sin >> netNodeCnt >> linkeCnt >> consumeNodeCnt; sin.str(topo[2]); sin >> serverCost; // 网络节点之间的边 int i, from, to, cap, cost; for(i=4; i<linkeCnt+4; i++) { sin.str(topo[i]); sin >> from >> to >> cap >> cost; addEdge(from, to, cap, cost, id); addEdge(to, from, 0, -cost, id); addEdge(to, from, cap, cost, id); addEdge(from, to, 0, -cost, id); //cout << from << " " << to << " " << cap << " " << cost << endl; node[from].id = from; node[from].degree++; node[to].id = to; node[to].degree++; } S = netNodeCnt; T = S + 1; // 超级源点与“消费节点连向的网络节点”之间的边 for(i=0; i<consumeNodeCnt; i++) { sin.str(topo[i+linkeCnt+5]); sin >> consume[i].ID >> consume[i].netID >> consume[i].demand; addEdge(S, consume[i].netID, consume[i].demand, 0, id); addEdge(consume[i].netID, S, 0, 0, id); F += consume[i].demand; mapConsume[consume[i].netID] = consume[i].ID; }}// 记录结果 void record_result(){ ostringstream sout; int n = bestPath.size(); sout << n << "\n" << "\n"; for (int p = 0; p < n; p++) { int j; for(j = bestPath[p].path.size()-2; j >=0; j--) { sout << bestPath[p].path[j] << " "; } sout << mapConsume[bestPath[p].path[0]] << " " << bestPath[p].flow; if(p != n-1) sout << "\n"; } result = sout.str(); //cout << result << endl;}// 最小费用流bool min_cost(int &cost, int nEdge, int nServer){ queue<int> q; int flow = 0; cost = serverCost * nServer; int i; for(i=0; i<nEdge; i++) edge[i].flow = 0; path.clear(); while(1) { memset(vis, false, sizeof(vis)); fill(dist, dist+netNodeCnt+2, INT_MAX); dist[S] = 0; q.push(S); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(i=head[u]; i!=-1; i=edge[i].next) { int v = edge[i].to; if(edge[i].cap > edge[i].flow && dist[v] > dist[u]+edge[i].cost) { dist[v] = dist[u] + edge[i].cost; preV[v] = u; preE[v] = i; if(!vis[v]) { q.push(v); vis[v] = true; } } } } if(dist[T] == INT_MAX) break; int f = INT_MAX; int u; for(u=T; u!=S; u=preV[u]) { int i = preE[u]; if (edge[i].cap - edge[i].flow < f) f = edge[i].cap - edge[i].flow; } for(u=T; u!=S; u=preV[u]) { int i = preE[u]; edge[i].flow += f; edge[i^1].flow -= f; } flow += f; cost += dist[T] * f; if(cost > minCost) return false; } if (flow >= F) { if (cost < minCost) { minCost = cost; bestPath.clear(); Result r; int f = 0; while(f < F) { int flow = INT_MAX; dfs(S, r, flow); f += flow; } } return true; } return false;}// 搜索路径void dfs(int u, Result &r, int &flow){ if(u == T) { r.flow = flow; for (int k = T; k != S; k = preV[k]) { int i = preE[k]; edge[i].flow -= flow; } bestPath.push_back(r); return; } for(int i=head[u]; i!=-1; i=edge[i].next) { int v = edge[i].to; if(edge[i].flow > 0) { preV[v] = u; preE[v] = i; r.path.push_back(v); if(edge[i].flow < flow) flow = edge[i].flow; dfs(v, r, flow); r.path.pop_back(); return; } }}/////////////////////////zkw////////////////////////////int min(int a, int b){ return a < b ? a : b;}// KM重标号bool adjust() { int v, min = INF; for (int i = 0; i < netNodeCnt+2; i++) { if (!vis[i]) continue; for (int j = head[i]; j != -1; j = edge[j].next) { v = edge[j].to; if (edge[j].cap > edge[j].flow) if (!vis[v] && dist[v] - dist[i] + edge[j].cost < min) min = dist[v] - dist[i] + edge[j].cost; } } if (min == INF) return false; for (int i = 0; i <netNodeCnt+2; i++) if (vis[i]) vis[i] = false, dist[i] += min; return true; } // 增广 int augment(int i, int flow) { if (i == T) { minCost += dist[S] * flow; maxflow += flow; return flow; } vis[i] = true; for (int j = head[i], v; v = edge[j].to, j != -1; j = edge[j].next) { if (edge[j].cap > edge[j].flow) { if (vis[v] || dist[v] + edge[j].cost != dist[i]) continue; int delta = augment(v, min(flow, edge[j].cap - edge[j].flow)); if (delta) { edge[j].flow += delta; edge[j ^ 1].flow -= delta; return delta; } } } return 0; } bool zkw(int &fit, int idx, int n) { for(int i=0; i<idx; i++) edge[i].flow = 0; memset(dist, 0, sizeof(dist)); minCost = maxflow = 0; for (int i = 0; i < netNodeCnt; i++) { vis[i] = false; } do { while (augment(S, INF)) memset(vis, false, sizeof(vis)); } while (adjust()); if (maxflow < F) return false; fit = minCost + n * serverCost; // 搜路径 bestPath.clear(); Result r; int f = 0; while(f < F) { int flow = INT_MAX; dfs(S, r, flow); f += flow; } return true; } /////////////////////////初始化时用到////////////////////// 最小费用流bool min_cost1(){ queue<int> q; int flow = 0; path.clear(); while(1) { memset(vis, false, sizeof(vis)); fill(dist, dist+netNodeCnt+2, INT_MAX); dist[S] = 0; q.push(S); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(int i=head[u]; i!=-1; i=edge[i].next) { int v = edge[i].to; if(edge[i].cap > edge[i].flow && dist[v] > dist[u]+edge[i].cost) { dist[v] = dist[u] + edge[i].cost; preV[v] = u; preE[v] = i; if(!vis[v]) { q.push(v); vis[v] = true; } } } } if(dist[T] == INT_MAX) break; int f = INT_MAX; int u; for(u=T; u!=S; u=preV[u]) { int i = preE[u]; if (edge[i].cap - edge[i].flow < f) f = edge[i].cap - edge[i].flow; } for(u=T; u!=S; u=preV[u]) { int i = preE[u]; edge[i].flow += f; edge[i^1].flow -= f; } flow += f; } bestPath.clear(); Result r; int f = 0; while(f < F) { int flow = INT_MAX1; dfs(S, r, flow); f += flow; } return true;}// 记录结果 void record_result1(set<int> &s){ int n = bestPath.size(); for (int p = 0; p < n; p++) { s.insert(bestPath[p].path[bestPath[p].path.size()-2]); } set<int>::iterator it; for(it = s.begin(); it != s.end(); it++) { vChoice.push_back(*it); }}////////////////////////随机算法//////////////////int Entity::getFit1(){ map<int, int> m; int cnt = position.size(); int fit = 0; // 保存之前的图 set<int>::iterator it; for(it = position.begin(); it != position.end(); it++) m[*it] = head[*it]; // 添加一些新边:放置服务器的网络节点连向超级汇点 int idx = id; for (it = position.begin(); it != position.end(); it++) { addEdge(*it, T, INT_MAX, 0, idx); addEdge(T, *it, 0, 0, idx); } bool find = zkw(fit, idx, position.size()); // 恢复之前的图 for (it = position.begin(); it != position.end(); it++) head[*it] = m[*it]; head[T] = -1; fitness = find ? fit : INT_MAX; return fitness;}int Entity::getFit(){ map<int, int> m; int cnt = position.size(); int fit = 0; // 保存之前的图 set<int>::iterator it; for(it = position.begin(); it != position.end(); it++) m[*it] = head[*it]; // 添加一些新边:放置服务器的网络节点连向超级汇点 int idx = id; for (it = position.begin(); it != position.end(); it++) { addEdge(*it, T, INT_MAX, 0, idx); addEdge(T, *it, 0, 0, idx); } bool find = min_cost(fit, idx, position.size()); // 恢复之前的图 for (it = position.begin(); it != position.end(); it++) head[*it] = m[*it]; head[T] = -1; fitness = find ? fit : INT_MAX; return fitness;}// 初始化void init(){ // 将所有的节点与汇点连边,费用为服务器费用 // 挑选度最大的2个点、带宽需求最高的2个点作为服务器 // 与汇点连边的费用为0 // 搜索最小费用路径,将所有倒数第2个点作为服务器,加入sChoice中 // 之后的搜索中,所有服务器都来自于sChoice set<int> s; for(int k=0; k<netNodeCnt; k++) s.insert(k); set<int> s1; s1.insert(node[0].id); // 度最高的2个点 s1.insert(node[1].id); Node node1[MAX_consumeNodeCnt]; for(int k=0; k<consumeNodeCnt; k++) { node1[k].id = consume[k].netID; node1[k].degree = consume[k].demand; } sort(node1, node1+consumeNodeCnt); s1.insert(node1[0].id); // 带宽需求最高的2个点 s1.insert(node1[1].id); // 保存之前的图 map<int, int> m; set<int>::iterator it; for(int k = 0; k < netNodeCnt; k++) m[k] = head[k]; for(it=s1.begin(); it != s1.end(); it++) { s.erase(*it); } int idx = id; for(it=s.begin(); it != s.end(); it++) { addEdge(*it, T, INT_MAX1, serverCost, idx); addEdge(T, *it, 0, 0, idx); } for(it=s1.begin(); it != s1.end(); it++) { addEdge(*it, T, INT_MAX1, 0, idx); addEdge(T, *it, 0, 0, idx); } min_cost1(); record_result1(sChoice); // 恢复之前的图 for (int k=0; k<netNodeCnt; k++) head[k] = m[k]; head[T] = -1; start = clock(); Best.position = sChoice; Best.getFit1();}bool accept(double delta, double temper){ if(delta <= 0) { if(Best.fitness > MostBest.fitness) MostBest = Best; return true; } //return rand() <= exp((-delta) / temper) * RAND_MAX; return exp((-delta) / temper) >= 0.1;} // 变异函数void mutate(){ int r = rand() % 100; int cnt = Best.position.size(); // 替换变异 if(r < PMUTATION1 && cnt > 0) { Entity M = Best; int a = rand() % vChoice.size(); // 随机选取一个节点 set<int>::iterator it; vector<int> v; for(it = M.position.begin(); it != M.position.end(); it++) v.push_back(*it); if(bad.count(vChoice[a])) // 如果该节点在禁忌表中 { if(rand() % 100 < 70) // 以0.3的概率重新选择一个节点 { int j = rand() % v.size(); M.position.insert(vChoice[a]); // 加进新的 M.position.erase(v[j]); // 删除旧的节点 M.getFit1(); if(accept(M.fitness - Best.fitness, temp)) Best = M; if(temp >= thold) temp *= decs; } } else { int j = rand() % v.size(); M.position.insert(vChoice[a]); // 加进新的 M.position.erase(v[j]); // 删除旧的节点 M.getFit1(); if(accept(M.fitness - Best.fitness, temp)) Best = M; if(temp >= thold) temp *= decs; } } // 删除变异 else if (r < PMUTATION2 && cnt > 0) { Entity M = Best; vector<int> v; set<int>::iterator it; for(it = M.position.begin(); it != M.position.end(); it++) v.push_back(*it); int i = rand() % cnt; // 随机选择变异个体中的某个服务器,要将其删除 M.position.erase(v[i]); // 除掉旧的 M.getFit1(); if(accept(M.fitness - Best.fitness, temp)) { Best = M; if(temp >= thold) temp *= decs; bad.insert(v[i]); } } // 增加变异 else { Entity M = Best; int a = rand() % vChoice.size(); // 另外一个服务器 if(!M.position.count(vChoice[a])) // 如果该节点未放置服务器 { if(bad.count(vChoice[a])) // 如果该节点在禁忌表中 { if(rand() % 100 < 70) // 以0.3的概率重新选择一个节点 { M.position.insert(vChoice[a]); // 加进新的 M.getFit1(); if(accept(M.fitness - Best.fitness, temp)) { Best = M; if(temp >= thold) temp *= decs; } } } else { M.position.insert(vChoice[a]); // 加进新的 M.getFit1(); if(accept(M.fitness - Best.fitness, temp)) { Best = M; if(temp >= thold) temp *= decs; } } } }}void mainEA(){ init(); double t = (double)clock() / CLOCKS_PER_SEC; //double t = T2.tv_sec - T1.tv_sec; while (t < 90) { mutate(); t = (double)clock() / CLOCKS_PER_SEC; //t = T2.tv_sec - T1.tv_sec; if(t > 75) { PMUTATION1 = 60; } } if(Best.fitness > MostBest.fitness) Best = MostBest; finish = clock(); double duration = (double) (finish-start)/CLOCKS_PER_SEC; //时间以秒为单位 cout << "时间:" << duration << endl; cout << "bestFit:" << Best.fitness << endl; cout << Best.position.size() << endl;}
—————————————主函数———————
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;}
—————————————非核心———————
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(...)#endifINLINE 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);}
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
lib_time.h
#ifndef __LIB_TIME_H__#define __LIB_TIME_H__//打印时间。入参为打印信息头void print_time(const char * const head);#endif
高级用例 case0.txt,800节点,3022条边,360个消费者节点
结果:104863
阅读全文
0 0
- 2017华为软挑---SPFA、ZKW、模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- 模拟退火
- ZKW,SPFA费用流模板
- 2016华为精英软件挑战赛初赛思路及代码-基于模拟退火算法
- 模拟退火算法
- 模拟退火算法
- Codeforces Round #426 (Div. 2) D. The Bakery(DP+线段树) 好题
- 2017.5.21入门组总结
- centos系统yum安装mysql
- POJO映射器的ModelMapper使用
- day8 socket编程CS模型完善错误处理
- 2017华为软挑---SPFA、ZKW、模拟退火
- BZOJ4897: [Thu Summer Camp2016]成绩单 DP
- java中两种不同的 string赋值比较
- Java 接口回调机制
- 复习spfa
- apache You don't have permission to access /test.php on this server解决方法
- 360一代加固脱壳方法总结
- LeetCode 448. Find All Numbers Disappeared in an Array(查找数组中没有出现的数字)
- linux 下搭建php服务器