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

原创粉丝点击