2017華爲軟件挑戰賽剛開始的時候,和隊友花了一個月的時間開始弄,期間艱難困苦,有喜有悲,最好的時候排名到第一名,最差的也跑到倒數了,學習了很多東西,也知道自己很多東西還不會,寫下留個紀念。
這個題目是在一定前提下,求最小費用流,我們的想法很簡單,就是先找到每條最短路徑,把所有消費節點看成一個超級匯點,然後隨機確定服務器,找到每次分配費用流時候的最短路徑,在該路徑上添加最大流量,直到滿足所有消費節點的流量位置,由於沒有很好的確定服務器,導致最後在找服務器方面廢了很多功夫,最後採取的策略是:先把所有消費節點放上服務器,然後隨機選擇若干服務器,一個一個刪除,找到刪除後能得到最低費用的服務器,然後刪掉這個服務器,繼續刪,一直刪到不能刪爲止,然後隨機添加服務器,替換當前服務器,從而得到當前最優~
用過退火算法,但是可能沒寫好,比直接隨機還差,最後直接隨機了,這個題目最好是用其他算法,之前結構已經定性了,就沒有改了,雖然有點遺憾,不過走到這裏已經不遺憾了。
其他算法可以選擇整數規劃、單純性、ZKW等其他最優解算法。現在比賽還沒結束,所以就發初賽的代碼吧,,,大家隨便看看就行~
最讓人失望的是:沒近4強,竟然發99塊錢的手環,真是low爆了,上去唱個歌都可以拿到的手環和音響就是99塊錢,前四是手機,幾千塊,差距太大了,不得不說,真的low爆了,對華爲很失望、車票也沒報,而且辦事效率太低,無語。
#include "deploy.h"
#include "stdio.h"
#include "stdlib.h"
#include "time.h"
#include <cstring>
#include <queue>
#include <iostream>
#include "math.h"
using namespace std;
#ifdef WIN32
#define LOCALTIME_R(t) localtime((t))
#else
#define LOCALTIME_R(t) localtime_r((t), (struct tm *)&tmres)
#endif
#define _DEBUG
#define INLINE static __inline
#ifdef _DEBUG
#define PRINT printf
#else
#define PRINT(...)
#endif
#define MODE_LOW 200
#define MODE_Middle 500
#define UsingDistance
#define UsingRoom
bool IsUsingRoom = false;
struct GraphStruct CurrentGragh; //當前得到的表結構體形式
struct GraphStruct CurrentGragh_Temp;
unsigned short ConnectedLength_Min[Max_NetNodeNum][Max_NetNodeNum] = { 0 }; //定義任意兩點之間最小距離
unsigned short ConnectedMin_ID[Max_NetNodeNum][Max_NetNodeNum] = { 0 }; //定義任意兩點這間最小距離的ID鏈接,起始點,終止點,結果上一個的編號
unsigned short ConnectedLength_Min_Temp[Max_NetNodeNum][Max_NetNodeNum] = { 0 }; //定義任意兩點之間最小距離
unsigned short ConnectedMin_ID_Temp[Max_NetNodeNum][Max_NetNodeNum] = { 0 }; //定義任意兩點這間最小距離的ID鏈接,起始點,終止點,結果上一個的編號
bool IsInited = false;
unsigned short ExpensePointID[Max_NetNodeNum] = { 0 }; //消費節點綁定的ID號,比實際的ID號大1,實際操作的時候減1
unsigned short SumLength[Max_NetNodeNum][2] = { 0 }; //所有的消費節點距離普通節點的距離之和
short Path[Max_NetNodeNum][Max_LineNum][Max_LineNum] = { 0 }; //消費節點路徑 一維:消費節點ID 二維:消費節點路徑條數 三維:路徑內容
unsigned short Path_Num[Max_NetNodeNum][2] = { 0 }; //一維:消費節點ID 二維:0表示這是當前ID的第幾條路徑,1表示該路徑有多少個點
unsigned short PathExpense[Max_NetNodeNum][Max_NetNodeNum] = { 0 }; //佔用帶寬 一維:消費節點ID 二維:佔用帶寬數
unsigned short UnsatifiedPoint[Max_NetNodeNum] = { 0 };//當前網絡不能滿足的點,編號+1,實際操作時減1
unsigned short UnsatifiedNum = 0; //未滿足的網絡編號數量
bool IsSatified = false;
unsigned short SelectedServerNum = 1; //選中節點的數量
unsigned short NetPathALL = 0; //總路徑條數
unsigned short PreSearchedPath[Max_NetNodeNum] = { 0 };//上一次服務器編號
unsigned short PreServerNum = 0; //上一次服務器數量
unsigned short NowSearchedPath[Max_NetNodeNum] = { 0 };//當前服務器編號
unsigned short NowServerNum = 0; //當前服務器數量
unsigned short DeleteNum = 0; //刪除的點號
unsigned long ChargeALL = 0; //所有費用計算
unsigned long PreChargeALL = 0; //所有費用計算
unsigned short Cant_Delete[Max_NetNodeNum] = { 0 };
unsigned int CantDeleteNum = 0;
unsigned short SinglePoint[Max_NetNodeNum] = { 0 }; //孤立節點編號
unsigned short SinglePointNum = 0; //孤立節點數量
unsigned short ConnectRelation[Max_NetNodeNum][Max_NetNodeNum] = { 0 }; //節點之間的鏈接關係
unsigned short ConnectNum[Max_NetNodeNum] = { 0 }; //與該節點的鏈接個數
unsigned short addnum[Max_NetNodeNum][2] = { 0 }; //服務器排序
unsigned short ExpenceClosedServer[Max_NetNodeNum][2] = { 0 }; //找消費節點最近的服務器
unsigned short BandWidth[TEXT_LineNum][4] = { 0 }; //0表示起始點,1表示終點,2表示流量,3表示單價
unsigned short BandWidthNum = 0; //普通節點文件行數
unsigned short ExpenseBandNeed[Max_NetNodeNum] = { 0 }; //消費節點需要的帶寬
unsigned short ExpensePointSum[Max_NetNodeNum][2] = { 0 }; //消費節點與和它最近的消費節點的點數累計 0表示累計數,1表示標號
/*****************************************************************************/
unsigned short ConnectedNodePoint[Max_NetNodeNum][MaxConnect] = { 0 }; //用來保存與消費節點相關的點,一維下標是消費節點編號,從0開始,二維下標是相關的點
unsigned short ConnectedNodePointNum[Max_NetNodeNum] = { 0 }; //用來保存與消費節點相關的點的個數
unsigned short ConnectedExpensePoint[Max_NetNodeNum][MaxConnect] = { 0 }; //用來保存普通節點被哪些消費節點遍歷了,一維是普通節點的編號,二維是消費節點的編號
unsigned short ConnectedExpensePointNum[Max_NetNodeNum] = { 0 }; //用來保存每個普通節點被遍歷了幾次
unsigned short NodeNum[Max_NetNodeNum][2] = { 0 }; //記錄普通節點相關的點數
unsigned short SortNode[Max_NetNodeNum] = { 0 }; //得到普通節點排序的結果
/*******************************************************************************/
//*****************************************************************************
//計算Dijstala所需要的變量以及更新服務器的變量
unsigned short SearchedPoint[Max_NetNodeNum] = { 0 }; //定義已經找到的點,找到的話置爲累計長度
unsigned short ConnectedMin_ID_Test[Max_NetNodeNum][Max_NetNodeNum] = { 0 }; //定義任意兩點這間最小距離的ID鏈接,起始點,終止點,結果上一個的編號
unsigned short PaiXu[Max_NetNodeNum] = { 0 };
unsigned short ConnectedNum_Pre[Max_NetNodeNum][2] = { 0 };//高位表示第幾個點,低位0表示被搜的編號,1表示搜到最小值的編號
unsigned short LastPoint[Max_NetNodeNum] = { 0 }; //一共找到的點數組
unsigned short SameLegthPoint[Max_NetNodeNum] = { 0 }; //當前層找到的最短路徑數組
unsigned short RepeatBuf[Max_NetNodeNum] = { 0 }; //重複的Buf
//********************************************************************************
//********************************************************************************
//模擬退火算法參數
#define Mapkob_Line 27
#define AccuracyOut 1
#define ControlT 10000000
#define ControlPara 0.3
#define Q 1.5
float ControlT_Para = 0;
unsigned short Mapkob_L = 0;
unsigned short CurrentServerBuf[Max_NetNodeNum]={0};
unsigned short CurrentServerNum = 0;
unsigned long CurrentExpense = MaxMoney;
//********************************************************************************
#define NewPointNum 4
void deploy_server(char * topo[MAX_EDGE_NUM], int line_num, char * filename)
{
time_t long_time_start, long_time_end;
time(&long_time_start); /* Get time as long integer. */
long int TimeRunning = 0;
// 需要輸出的內容
//char * topo_file2 = (char *)"17\n\n0 8 0 20\n21 8 0 20\n9 11 1 13\n21 22 2 20\n23 22 2 8\n1 3 3 11\n24 3 3 17\n27 3 3 26\n24 3 3 10\n18 17 4 11\n1 19 5 26\n1 16 6 15\n15 13 7 13\n4 5 8 18\n2 25 9 15\n0 7 10 10\n23 24 11 23";
char topo_file[MAX_EDGE_NUM] = { 0 };
unsigned short TopoNum = 0;
GetGraph(topo, line_num); //獲取圖表信息
if (CurrentGragh.NetNodeNum <= MODE_LOW) IsUsingRoom = false; //判斷工作類型,點數少時使用距離計算
else IsUsingRoom = true; //點數多時用容量計算
//判斷孤立節點
GetSinglePoint(); //尋找孤立節點
LenthSum(); //確定服務器排序
SelectedServerNum = 40; //從3個服務器開始搜
UnsatifiedNum = CurrentGragh.ExpenseNum;
NowServerNum = SelectedServerNum;
PreServerNum = SelectedServerNum;
GetExpenseMin();
if (true)
{
NowServerNum = 0; PreServerNum = 0;
for (int i = 0; i < CurrentGragh.ExpenseNum; i++)
{
NowSearchedPath[NowServerNum++] = ExpensePointID[i] - 1;
PreSearchedPath[PreServerNum++] = ExpensePointID[i] - 1;
}
UpdateMaxie(); //更新數據矩陣
UpdateServerAll(NowServerNum);//更新服務器位置
IsSatified = GetMaxFlow(); //計算並判斷是否滿足情況
if (IsSatified == true) ChargeALL = GetCharge(topo_file, false);//得到當前方案滿足的錢數
}
if (CurrentGragh.NetNodeNum <= MODE_LOW) { PreServerNum = NowServerNum; NowServerNum = NowServerNum; ChargeALL = MaxMoney; }//點數小時,全局搜索找最優
else if (CurrentGragh.NetNodeNum <= MODE_Middle) { PreServerNum = NowServerNum; PreServerNum = NowServerNum; ChargeALL = MaxMoney; } //中級
else {PreServerNum = NowServerNum = NowServerNum;} //高級
SelectedServerNum = NowServerNum; //服務器個數
PreServerNum = SelectedServerNum;
NowServerNum = SelectedServerNum; //重新賦值
PreChargeALL = ChargeALL; //保存上次錢數
static long TempCharge = PreChargeALL;
static long TempDeleteNum = 0;
static bool IsDelete = false;
static float aaa;
static float bbb;
int Temp1 = 0;
ControlT_Para = ControlT;
//****************************************************************初中級方案 start*********************************************************************
while (CurrentGragh.NetNodeNum <= MODE_Middle)
{
for (int i = PreServerNum - 1; i >= 0; i--) //循環次數
{
time(&long_time_end); /* Get time as long integer. */
TimeRunning = long_time_end - long_time_start;
if (TimeRunning >= 89) break;
UpdateMaxie(); //更新數據矩陣
DeleteNum = i; NowServerNum = 0;
for (int DeleteCheck = 0; DeleteCheck < CantDeleteNum; DeleteCheck++)
{
if (DeleteNum == Cant_Delete[DeleteCheck])
{
IsDelete = true;
break;
}
}
if (IsDelete == true) { IsDelete = false; continue; }
for (int j = 0; (j < PreServerNum); j++)
{
if ((j != DeleteNum))
NowSearchedPath[NowServerNum++] = PreSearchedPath[j];//更新路徑
}
SelectedServerNum = NowServerNum; //當前點數
UpdateServerAll(NowServerNum);//更新服務器位置
IsSatified = GetMaxFlow(); //計算並判斷是否滿足情況
if (IsSatified == true)
{
ChargeALL = GetCharge(topo_file, false); //得到當前方案的錢數
if (TempCharge > ChargeALL) { TempCharge = ChargeALL; TempDeleteNum = DeleteNum; }//if (CurrentGragh.NetNodeNum > MODE_Middle) break; }
}
else
{
bool IsCanInput = true;
for (int l = 0; l < CantDeleteNum; l++)
{
if (PreSearchedPath[DeleteNum] == Cant_Delete[l]) IsCanInput = false;
}
if (IsCanInput == true) Cant_Delete[CantDeleteNum++] = PreSearchedPath[DeleteNum];
continue;
}
}
if (TempCharge < PreChargeALL)
{
NowServerNum = PreServerNum; PreServerNum = 0;
PreChargeALL = TempCharge;
for (int j = 0; (j < NowServerNum); j++)
{
if ((j != TempDeleteNum))
PreSearchedPath[PreServerNum++] = PreSearchedPath[j];//更新路徑
}
}
else if (TempCharge == PreChargeALL) break;
}
//加點刪除策略***************************************************************************************
if (CurrentGragh.NetNodeNum <= MODE_Middle)
{
CurrentServerNum = 0;
for (int i = 0; i < PreServerNum; i++) CurrentServerBuf[CurrentServerNum++] = PreSearchedPath[i];
TempCharge = MaxMoney; CurrentExpense = PreChargeALL; PreChargeALL = MaxMoney;
}
while (CurrentGragh.NetNodeNum <= MODE_Middle)
{
time(&long_time_end); /* Get time as long integer. */
TimeRunning = long_time_end - long_time_start;
if (TimeRunning >= 89) break;
PreServerNum = 0;
for (int i = 0; i < CurrentServerNum; i++) PreSearchedPath[PreServerNum++] = CurrentServerBuf[i];
TempCharge = MaxMoney; PreChargeALL = MaxMoney;
unsigned short AddPointNum = 0;
unsigned short PointTemp = 0;
for (int i = 0; i < NewPointNum;) //添加隨機點
{
PointTemp = rand() % (CurrentGragh.NetNodeNum - 1); //產生0-PreServerNum-1的隨機數
bool IsInBuf = false;
for (int j = 0; j < PreServerNum; j++)
{
if (PointTemp == PreSearchedPath[j])
{
IsInBuf = true;
break;
}
}
if (IsInBuf == true) continue;
PreSearchedPath[PreServerNum++] = PointTemp;
i++;
}
memset(Cant_Delete, 0, Max_NetNodeNum*sizeof(unsigned short));
while (CurrentGragh.NetNodeNum <= MODE_Middle)
{
for (int i = PreServerNum - 1; i >= 0; i--) //循環次數
{
time(&long_time_end); /* Get time as long integer. */
TimeRunning = long_time_end - long_time_start;
if (TimeRunning >= 89) break;
UpdateMaxie(); //更新數據矩陣
DeleteNum = i; NowServerNum = 0;
for (int DeleteCheck = 0; DeleteCheck < CantDeleteNum; DeleteCheck++)
{
if (DeleteNum == Cant_Delete[DeleteCheck])
{
IsDelete = true;
break;
}
}
if (IsDelete == true) { IsDelete = false; continue; }
for (int j = 0; (j < PreServerNum); j++)
{
if ((j != DeleteNum))
NowSearchedPath[NowServerNum++] = PreSearchedPath[j];//更新路徑
}
SelectedServerNum = NowServerNum; //當前點數
UpdateServerAll(NowServerNum);//更新服務器位置
IsSatified = GetMaxFlow(); //計算並判斷是否滿足情況
if (IsSatified == true)
{
ChargeALL = GetCharge(topo_file, false); //得到當前方案的錢數
if (TempCharge > ChargeALL) { TempCharge = ChargeALL; TempDeleteNum = DeleteNum; }//if (CurrentGragh.NetNodeNum > MODE_Middle) break; }
}
else
{
bool IsCanInput = true;
for (int l = 0; l < CantDeleteNum; l++)
{
if (PreSearchedPath[DeleteNum] == Cant_Delete[l]) IsCanInput = false;
}
if (IsCanInput == true) Cant_Delete[CantDeleteNum++] = PreSearchedPath[DeleteNum];
continue;
}
}
if (TempCharge < PreChargeALL)
{
NowServerNum = PreServerNum; PreServerNum = 0;
PreChargeALL = TempCharge;
for (int j = 0; (j < NowServerNum); j++)
{
if ((j != TempDeleteNum))
PreSearchedPath[PreServerNum++] = PreSearchedPath[j];//更新路徑
}
}
else if (TempCharge == PreChargeALL) break;
}
if (CurrentExpense > PreChargeALL)
{
CurrentServerNum = 0; CurrentExpense = PreChargeALL;
for (int i = 0; i < PreServerNum; i++)
CurrentServerBuf[CurrentServerNum++] = PreSearchedPath[i];
}
PRINT("當前費用:%d", CurrentExpense);
PRINT("計算費用:%d", PreChargeALL);
PRINT(" 當前時間:%d", TimeRunning);
PRINT(" 當前服務器數:%d\n", PreServerNum);
}
if (CurrentGragh.NetNodeNum < MODE_Middle)
{
PreServerNum = 0; PreChargeALL = CurrentExpense;
for (int i = 0; i < CurrentServerNum; i++) PreSearchedPath[PreServerNum++] = CurrentServerBuf[i];
}
//****************************************************************高級方案 start*********************************************************************
while (CurrentGragh.NetNodeNum > MODE_Middle)
{
for (int MapkobLine = 0; MapkobLine < Mapkob_Line; MapkobLine++) //Mapkob 鏈長
{
time(&long_time_end); /* Get time as long integer. */
TimeRunning = long_time_end - long_time_start;
if (TimeRunning >= 90) break;
UpdateMaxie(); //更新數據矩陣
DeleteNum = rand() % (PreServerNum - 1); //產生0-PreServerNum-1的隨機數
NowServerNum = 0;
for (int DeleteCheck = 0; DeleteCheck < CantDeleteNum; DeleteCheck++)
{
if (DeleteNum == Cant_Delete[DeleteCheck])
{
IsDelete = true;
break;
}
}
if (IsDelete == true) { IsDelete = false; continue; }
for (int j = 0; (j < PreServerNum); j++)
{
if ((j != DeleteNum))
NowSearchedPath[NowServerNum++] = PreSearchedPath[j];//更新路徑
}
SelectedServerNum = NowServerNum; //當前點數
UpdateServerAll(NowServerNum);//更新服務器位置
IsSatified = GetMaxFlow(); //計算並判斷是否滿足情況
if (IsSatified == true)
{
ChargeALL = GetCharge(topo_file, false); //得到當前方案的錢數
if (TempCharge > ChargeALL) { TempCharge = ChargeALL; TempDeleteNum = DeleteNum; }//if (CurrentGragh.NetNodeNum > MODE_Middle) break; }
}
else
{
bool IsCanInput = true;
for (int l = 0; l < CantDeleteNum; l++)
{
if (PreSearchedPath[DeleteNum] == Cant_Delete[l]) IsCanInput = false;
}
if (IsCanInput == true) Cant_Delete[CantDeleteNum++] = PreSearchedPath[DeleteNum];
continue;
}
}
if (TempCharge < PreChargeALL)
{
NowServerNum = PreServerNum; PreServerNum = 0;
PreChargeALL = TempCharge;
for (int j = 0; (j < NowServerNum); j++)
{
if ((j != TempDeleteNum))
PreSearchedPath[PreServerNum++] = PreSearchedPath[j];//更新路徑
}
}
else if (TempCharge == PreChargeALL) break;
PRINT("當前費用:%d", PreChargeALL);
PRINT(" 當前時間:%d", TimeRunning);
PRINT(" 當前服務器數:%d\n", NowServerNum);
}
SelectedServerNum = NowServerNum;
NowServerNum = PreServerNum; NetPathALL = 0;
if (CurrentGragh.NetNodeNum <= MODE_Middle) //初級和中級,服務器交換
{
for (int i = 0; i < NowServerNum; i++) NowSearchedPath[i] = PreSearchedPath[i];
for (int i = 0; i < CurrentGragh.ExpenseNum; i++) //判斷某個消費節點是不是服務器
{
bool IsServer = false;
unsigned short SearchedServerNum = 0;
for (int j = 0; j < NowServerNum; j++) //判斷該消費節點是不是服務器,是第幾個服務器
{
if (ExpensePointID[i] - 1 == NowSearchedPath[j])
{
IsServer = true;
SearchedServerNum = j;
break;
}
}
if (IsServer == false) continue;//如果該消費節點不是服務器,直接繼續搜消費節點上的服務器
//找到與該消費節點最近的消費節點,判斷是不是服務器
unsigned short ClosedLength = MaxERROR,CloseNum=0,Temp=0;
for (int j = 0; j < CurrentGragh.ExpenseNum; j++) //找到最短路徑的消費節點
{
if (j != i)
{
Temp = ConnectedLength_Min_Temp[ExpensePointID[i] - 1][ExpensePointID[j] - 1];//當前距離
if (Temp < ClosedLength)
{
ClosedLength = Temp;
CloseNum = j;
}
}
}
IsServer = false;
for (int j = 0; j < NowServerNum; j++) //判斷該消費節點是不是服務器,是第幾個服務器
{
if (ExpensePointID[CloseNum] - 1 == NowSearchedPath[j])
{
IsServer = true;
SearchedServerNum = j;
break;
}
}
if (IsServer == false) //如果該節點不是服務器,把該節點置爲服務器,交換
{
NowSearchedPath[SearchedServerNum] = ExpensePointID[CloseNum] - 1;
UpdateMaxie(); //更新數據矩陣
UpdateServerAll(NowServerNum); //更新服務器位置
IsSatified = GetMaxFlow(); //計算並判斷是否滿足情況
ChargeALL = GetCharge(topo_file, false); //得到當前方案的錢數
if ((IsSatified==true)&&(ChargeALL < PreChargeALL)) //當前錢數降了
{
continue;
}
else
{
NowSearchedPath[SearchedServerNum] = ExpensePointID[i] - 1;
}
}
}
}
else
{
//for (int i = 0; i < CurrentServerNum; i++) NowSearchedPath[i] = CurrentServerBuf[i];
NowServerNum = PreServerNum;
for (int i = 0; i < NowServerNum; i++) NowSearchedPath[i] = PreSearchedPath[i];
}
//當前算得的點數大於消費節點數,或者當前消費大於直接放在服務器的消費數,直接把服務器放在消費節點位置上
if ((NowServerNum >= CurrentGragh.ExpenseNum) || (PreChargeALL>CurrentGragh.ExpenseNum*CurrentGragh.ServerCost))
{
PreServerNum = CurrentGragh.ExpenseNum;
NowServerNum = CurrentGragh.ExpenseNum;
for (int i = 0; i < CurrentGragh.ExpenseNum; i++)
{
NowSearchedPath[i] = ExpensePointID[i] - 1; //服務器位置
}
}
UpdateMaxie(); //更新數據矩陣
UpdateServerAll(NowServerNum); //更新服務器位置
IsSatified = GetMaxFlow(); //計算並判斷是否滿足情況
ChargeALL = GetCharge(topo_file, true); //得到當前方案的錢數
if (IsSatified == true) PRINT("\n答案正確!\n");
else PRINT("\n答案錯誤!\n");
/*
char aaa[2];
itoa(10, aaa, 10);*/
unsigned short PreID = 0;
unsigned short NowID = 0;
int kk = 0;
bool IsContinue = false;
//*************************************************寫入文件系統start****************************************************//
sprintf(&topo_file[0], "%ld", NetPathALL); while ((topo_file[TopoNum] >= 0x30) && (topo_file[TopoNum] <= 0x39)) TopoNum++;
sprintf(&topo_file[TopoNum++], "%s", "\n"); sprintf(&topo_file[TopoNum++], "%s", "\n");
for (int x = 0; x < NowServerNum; x++)
{
for (int i = 0; i < CurrentGragh.ExpenseNum; i++) //消費節點
{
for (int j = 0; j < Path_Num[i][0]; j++) //消費節點邊數
{
PreID = ExpensePointID[i] - 1;//消費節點ID
kk = 0;
for (kk = 0; Path[i][j][kk] != -1; kk++) {} kk--;
if (kk == -1) kk = 0;
if ((Path[i][j][kk] == NowSearchedPath[x]))
IsContinue = true;
if (IsContinue == true)
{
while (kk >= 0)
{
sprintf(&topo_file[TopoNum], "%ld", Path[i][j][kk]); while ((topo_file[TopoNum] >= 0x30) && (topo_file[TopoNum] <= 0x39)) TopoNum++;
sprintf(&topo_file[TopoNum], "%s", " "); TopoNum++;
kk--;
}
sprintf(&topo_file[TopoNum], "%ld", ExpensePointID[i] - 1); while ((topo_file[TopoNum] >= 0x30) && (topo_file[TopoNum] <= 0x39)) TopoNum++;
sprintf(&topo_file[TopoNum], "%s", " "); TopoNum++;
sprintf(&topo_file[TopoNum], "%ld", i); while ((topo_file[TopoNum] >= 0x30) && (topo_file[TopoNum] <= 0x39)) TopoNum++;
sprintf(&topo_file[TopoNum], "%s", " "); TopoNum++;
sprintf(&topo_file[TopoNum], "%ld", PathExpense[i][j]); while ((topo_file[TopoNum] >= 0x30) && (topo_file[TopoNum] <= 0x39)) TopoNum++;
if ((x != NowServerNum - 1) || (i != CurrentGragh.ExpenseNum - 1) || (j != Path_Num[i][0] - 1))
{
sprintf(&topo_file[TopoNum], "%s", "\n"); TopoNum += 1;
}
}
else if (ExpensePointID[i] - 1 == NowSearchedPath[x])
{
sprintf(&topo_file[TopoNum], "%ld", ExpensePointID[i] - 1); while ((topo_file[TopoNum] >= 0x30) && (topo_file[TopoNum] <= 0x39)) TopoNum++;
sprintf(&topo_file[TopoNum], "%s", " "); TopoNum++;
sprintf(&topo_file[TopoNum], "%ld", i); while ((topo_file[TopoNum] >= 0x30) && (topo_file[TopoNum] <= 0x39)) TopoNum++;
sprintf(&topo_file[TopoNum], "%s", " "); TopoNum++;
sprintf(&topo_file[TopoNum], "%ld", PathExpense[i][j]); while ((topo_file[TopoNum] >= 0x30) && (topo_file[TopoNum] <= 0x39)) TopoNum++;
if ((x != NowServerNum - 1) || (i != CurrentGragh.ExpenseNum - 1) || (j != Path_Num[i][0] - 1))
{
sprintf(&topo_file[TopoNum], "%s", "\n"); TopoNum += 1;
}
}
IsContinue = false;
}
}
}
if (topo_file[TopoNum - 1] == 0x0a) topo_file[TopoNum - 1] = 0;
//*************************************************寫入文件系統end****************************************************//
// 直接調用輸出文件的方法輸出到指定文件中(ps請注意格式的正確性,如果有解,第一行只有一個數據;第二行爲空;第三行開始纔是具體的數據,數據之間用一個空格分隔開)
write_result(topo_file, filename);
}
/*********************************************
函數名:GetNum(char * graph[MAX_EDGE_NUM],unsigned short X_Line,bool Isclear)
函數功能:得到數據
函數變量:graph[MAX_EDGE_NUM],unsigned short X_Line,bool Isclear
函數返回值:unsined int
**********************************************/
unsigned short GetNum(char * graph[MAX_EDGE_NUM], unsigned short X_Line)
{
unsigned short RetureValue = 0;
static unsigned char Y_Line = 0;
static unsigned short X_Line_Last = 0;
if (X_Line_Last != X_Line) Y_Line = 0;
while ((*(graph[X_Line] + Y_Line) < 0x30) || (*(graph[X_Line] + Y_Line)>0x39)) Y_Line++;
while ((*(graph[X_Line] + Y_Line) >= 0x30) && (*(graph[X_Line] + Y_Line) <= 0x39))
{
RetureValue = RetureValue * 10 + *(graph[X_Line] + Y_Line) - 0x30;
Y_Line++;
}
X_Line_Last = X_Line;
return RetureValue;
}
/*********************************************
函數名:GetGraph(char * graph[MAX_EDGE_NUM])
函數功能:導入文件,生成圖數組
函數變量:graph[MAX_EDGE_NUM]
函數返回值:null
**********************************************/
void GetGraph(char * graph_input[MAX_EDGE_NUM], int edge_num_input)
{
int i = 0, j = 0;
unsigned short Net_X, Net_Y;
static bool IsFirstInput = false;
if (IsFirstInput == true) return;
while ((graph_input[i][0] < 0x30) || (graph_input[i][0]>0x39)) i++; //獲取第一行點數、鏈路數、消費節點數
CurrentGragh.NetNodeNum = GetNum(graph_input, i);
CurrentGragh.NetLinkNum = GetNum(graph_input, i);
CurrentGragh.ExpenseNum = GetNum(graph_input, i); i++;
while ((graph_input[i][0] < 0x30) || (graph_input[i][0]>0x39)) i++; //獲取第三行,服務器價格
CurrentGragh.ServerCost = GetNum(graph_input, i); i++;
while ((graph_input[i][0] < 0x30) || (graph_input[i][0]>0x39)) i++;
while ((graph_input[i][0] >= 0x30) && (graph_input[i][0] <= 0x39)) //獲取普通網絡節點的鏈接關係,生成鏈接矩陣
{
Net_X = GetNum(graph_input, i);
Net_Y = GetNum(graph_input, i);
//CurrentGragh.Net_Graph[Net_X][Net_Y].NetMode = Normal_Net;
//CurrentGragh.Net_Graph[Net_Y][Net_X].NetMode = Normal_Net;
CurrentGragh.Net_Graph[Net_X][Net_Y].BandWidth_Max =
CurrentGragh.Net_Graph[Net_Y][Net_X].BandWidth_Max = GetNum(graph_input, i);
CurrentGragh.Net_Graph[Net_X][Net_Y].SingleCost =
CurrentGragh.Net_Graph[Net_Y][Net_X].SingleCost = GetNum(graph_input, i);
BandWidth[BandWidthNum][0] = Net_X;
BandWidth[BandWidthNum][1] = Net_Y;
BandWidth[BandWidthNum][2] = CurrentGragh.Net_Graph[Net_X][Net_Y].BandWidth_Max;
BandWidth[BandWidthNum++][3] = CurrentGragh.Net_Graph[Net_X][Net_Y].SingleCost;
if (IsFirstInput == false)
{
ConnectRelation[Net_X][ConnectNum[Net_X]++] = Net_Y;
ConnectRelation[Net_Y][ConnectNum[Net_Y]++] = Net_X;
}
i++;
}
while ((graph_input[i][0] < 0x30) || (graph_input[i][0]>0x39)) i++;
short ExpenseLine = 0;
while ((ExpenseLine<CurrentGragh.ExpenseNum)&&(graph_input[i][0] >= 0x30) && (graph_input[i][0] <= 0x39)) //獲得消費節點鏈接關係,生成消費矩陣
{
Net_X = GetNum(graph_input, i);
Net_Y = GetNum(graph_input, i);
CurrentGragh.Net_Graph[Net_X + CurrentGragh.NetNodeNum][Net_Y].ConnectID = Net_Y;
CurrentGragh.Net_Graph[Net_Y][Net_X + CurrentGragh.NetNodeNum].ConnectID = Net_Y;
//CurrentGragh.Net_Graph[Net_X + CurrentGragh.NetNodeNum][Net_Y].NetMode = Expense_Net;
//CurrentGragh.Net_Graph[Net_Y][Net_X + CurrentGragh.NetNodeNum].NetMode = Expense_Net;
CurrentGragh.Net_Graph[Net_Y][Net_X + CurrentGragh.NetNodeNum].BandWidth_Need =
CurrentGragh.Net_Graph[Net_X + CurrentGragh.NetNodeNum][Net_Y].BandWidth_Need = GetNum(graph_input, i);
ExpensePointID[Net_X] = Net_Y + 1;
ExpenseBandNeed[Net_X] = CurrentGragh.Net_Graph[Net_X + CurrentGragh.NetNodeNum][Net_Y].BandWidth_Need;
i++; ExpenseLine++;
}
IsFirstInput = true;
}
/*********************************************
函數名:unsigned short Dijkstra_Graph(struct ParaNetStruct GraphNet[Max_NetNodeNum][Max_NetNodeNum])
函數功能:導入圖像矩陣,計算初始點和結束點最短距離
函數變量:Start_Point:初始點 End_Point:結束點
函數返回值:節點距離
**********************************************/
//unsigned short Dijkstra_Graph(unsigned short Start_Point, unsigned short End_Point)
//{
// unsigned short Connect_Min = MaxERROR; //定義與某一點相連的路徑最小值
// unsigned short Current_Aspect = 0; //當前層,或者與當前尋找的次數
// unsigned short SearchedPoint[1000] = { 0 }; //定義已經找到的點,找到的話置爲累計長度
// unsigned short Current_Point = 0; //當前點
// unsigned short SameLegthNum = 0; //當前層找到的最小路徑數量
// unsigned short SameLegthPoint[1000] = { 0 }; //當前層找到的最短路徑數組
// unsigned short i = 0;
// unsigned short Sum_Legtgh = 0; //累計長度
// int LastNum = 1; //一共找到的點數
// unsigned short LastPoint[1000] = { 0 }; //一共找到的點數組
// LastPoint[0] = Start_Point; //第一次賦值
// unsigned short ConnectedNum_Pre[1000][2] = { 0 };//高位表示第幾個點,低位0表示被搜的編號,1表示搜到最小值的編號
//
// for (Current_Aspect = 0; Current_Aspect < CurrentGragh.NetNodeNum; Current_Aspect++) //表示是第幾次尋找
// {
// for (int n = 0; n < LastNum; n++)
// {
// Current_Point = LastPoint[n];
// if ((SearchedPoint[Current_Point] != 0) || (Current_Point == Start_Point)) //此點已經存在,即已經被搜尋過
// {
// for (int k = 0; k < ConnectNum[Current_Point]; k++)
// {
// i = ConnectRelation[Current_Point][k];
// if ((i != Start_Point) && (Connect_Min >= SearchedPoint[Current_Point] + CurrentGragh.Net_Graph[Current_Point][i].SingleCost) && (CurrentGragh.Net_Graph[Current_Point][i].BandWidth_Max != 0) && (SearchedPoint[i] == 0)) //找到這一層的最小值
// {
// if (Connect_Min>SearchedPoint[Current_Point] + CurrentGragh.Net_Graph[Current_Point][i].SingleCost) //最小值更新
// {
// SameLegthNum = 0;
// }
// Connect_Min = SearchedPoint[Current_Point] + CurrentGragh.Net_Graph[Current_Point][i].SingleCost; //當前最小值
// ConnectedNum_Pre[SameLegthNum][0] = Current_Point; //記錄被搜的編號
// ConnectedNum_Pre[SameLegthNum][1] = i; //記錄搜到最小值的編號
// SameLegthPoint[SameLegthNum++] = i; //記錄最小值個數以及座標
// }
// }
// }
// }
//
// if (SameLegthNum == 0) break; //沒有找到點,退出搜索
// for (i = 0; i < SameLegthNum; i++)
// {
// SearchedPoint[SameLegthPoint[i]] = Connect_Min; //放入最短長度
// ConnectedLength_Min[Start_Point][SameLegthPoint[i]] = Connect_Min;//最小距離放入鏈接數組
// ConnectedMin_ID[Start_Point][ConnectedNum_Pre[i][1]] = ConnectedNum_Pre[i][0];
//
// if (IsInited == false)
// {
// ConnectedLength_Min_Temp[Start_Point][SameLegthPoint[i]] = Connect_Min;
// ConnectedLength_Min_Temp[SameLegthPoint[i]][Start_Point] = Connect_Min; //最小距離放入鏈接數組
// ConnectedMin_ID_Temp[Start_Point][ConnectedNum_Pre[i][1]] = ConnectedNum_Pre[i][0];
// }
//
// LastPoint[LastNum++] = SameLegthPoint[i]; //記錄已經被找過的點數
// if (SameLegthPoint[i] == End_Point)
// return Connect_Min;
// }
// SameLegthNum = 0; Connect_Min = MaxERROR; //累計清零
// }
//}
/*********************************************
函數名:void Dijkstra_Graph_2(unsigned short Start_Point)
函數功能:導入圖像矩陣,計算其他所有節點到初始節點最短距離
函數變量:Start_Point:初始點
函數返回值:null
**********************************************/
void Dijkstra_Graph_2(unsigned short Start_Point)
{
unsigned short Connect_Min = MaxERROR; //定義與某一點相連的路徑最小值
unsigned short Current_Aspect = 0; //當前層,或者與當前尋找的次數
unsigned short Current_Point = 0; //當前點
unsigned short SameLegthNum = 0; //當前層找到的最小路徑數量
unsigned short i = 0;
unsigned short Sum_Legtgh = 0; //累計長度
int LastNum = 1; //一共找到的點數
memset(SearchedPoint, 0, Max_NetNodeNum*sizeof(unsigned short));
LastPoint[0] = Start_Point; //第一次賦值
for (Current_Aspect = 0; Current_Aspect < CurrentGragh.NetNodeNum; Current_Aspect++) //表示是第幾次尋找
{
for (int n = 0; n < LastNum; n++)
{
Current_Point = LastPoint[n];
if ((SearchedPoint[Current_Point] != 0) || (Current_Point == Start_Point)) //此點已經存在,即已經被搜尋過
{
for (int k = 0; k < ConnectNum[Current_Point]; k++)
{
i = ConnectRelation[Current_Point][k];
if ((i != Start_Point) && (Connect_Min >= SearchedPoint[Current_Point] + CurrentGragh.Net_Graph[Current_Point][i].SingleCost) && (CurrentGragh.Net_Graph[Current_Point][i].BandWidth_Max != 0) && (SearchedPoint[i] == 0)) //找到這一層的最小值
{
if (Connect_Min>SearchedPoint[Current_Point] + CurrentGragh.Net_Graph[Current_Point][i].SingleCost) //最小值更新
{
SameLegthNum = 0;
}
Connect_Min = SearchedPoint[Current_Point] + CurrentGragh.Net_Graph[Current_Point][i].SingleCost; //當前最小值
ConnectedNum_Pre[SameLegthNum][0] = Current_Point; //記錄被搜的編號
ConnectedNum_Pre[SameLegthNum][1] = i; //記錄搜到最小值的編號
SameLegthPoint[SameLegthNum++] = i; //記錄最小值個數以及座標
}
}
}
}
if (SameLegthNum == 0) break; //沒有找到點,退出搜索
for (i = 0; i < SameLegthNum; i++)
{
SearchedPoint[SameLegthPoint[i]] = Connect_Min; //放入最短長度
ConnectedLength_Min[Start_Point][SameLegthPoint[i]] = Connect_Min;
ConnectedMin_ID[Start_Point][ConnectedNum_Pre[i][1]] = ConnectedNum_Pre[i][0];
if (IsInited == false)
{
ConnectedLength_Min_Temp[Start_Point][SameLegthPoint[i]] = Connect_Min;
ConnectedLength_Min_Temp[SameLegthPoint[i]][Start_Point] = Connect_Min; //最小距離放入鏈接數組
ConnectedMin_ID_Temp[Start_Point][ConnectedNum_Pre[i][1]] = ConnectedNum_Pre[i][0];
}
LastPoint[LastNum++] = SameLegthPoint[i]; //記錄已經被找過的點數
}
SameLegthNum = 0; Connect_Min = MaxERROR; //累計清零
}
}
/*********************************************
函數名:unsigned short MinPoint( unsigned short servernum, unsigned short expensepoint)
函數功能:選出與該消費節點相連的最短的服務器
函數變量:servernum是服務器的個數,expensepoint是消費節點的ID
函數返回值:服務器標號
**********************************************/
unsigned short MinPoint(unsigned short servernum, unsigned short expensepoint)//servernum是服務器的個數,expensepoint是消費節點的ID,選出與該消費節點相連的最短的服務器
{
unsigned short i = 0;
unsigned short MinServerPoint = 0;
unsigned short MiniPath = MaxERROR;
for (i = 0; i < servernum; i++)
{
if (ConnectedLength_Min[expensepoint][NowSearchedPath[i]] < MiniPath)
{
MiniPath = ConnectedLength_Min[expensepoint][NowSearchedPath[i]];
MinServerPoint = NowSearchedPath[i];
}
}
return MinServerPoint;
}
/*********************************************
函數名:void LenthSum()
函數功能:計算所有消費節點到任意節點最短距離總和
函數變量:null
函數返回值:null
**********************************************/
void LenthSum()
{
#ifdef UsingDistance
if (IsUsingRoom == false)
{
static unsigned short Sum = 0;
for (int i = 0; i < CurrentGragh.NetNodeNum; i++)
{
Dijkstra_Graph_2(i);//找第i個節點所有連接距離
for (int j = 0; j < CurrentGragh.ExpenseNum; j++)
{
Sum += ConnectedLength_Min[i][ExpensePointID[j] - 1];
}
//PRINT("到%d結點距離:%d\n", i, Sum);
SumLength[i][0] = Sum;
SumLength[i][1] = i;
for (int k = 0; k < SinglePointNum; k++)
{
if (i == ExpensePointID[SinglePoint[k]] - 1)
{
SumLength[i][0] = 0;
SumLength[i][1] = i;
break;
}
}
Sum = 0;
}
MaoPao(SumLength, CurrentGragh.NetNodeNum);
for (int i = 0; i < CurrentGragh.NetNodeNum; i++)
{
PreSearchedPath[PreServerNum++] = SumLength[i][1];//保存第一次計算的路徑排序
NowSearchedPath[NowServerNum++] = SumLength[i][1];
//PRINT("到%d結點距離:%d\n", SumLength[i][1], SumLength[i][0]);
}
IsInited = true;
}
#endif // UsingDistance
#ifdef UsingRoom
if (IsUsingRoom == true)
{
unsigned short Sum = 0;
unsigned short LineNum = 0;
for (int i = 0; i < CurrentGragh.NetNodeNum; i++)
{
Dijkstra_Graph_2(i);//找第i個節點所有連接距離
for (int j = 0; j < CurrentGragh.NetNodeNum; j++)
{
Sum += CurrentGragh.Net_Graph[i][j].BandWidth_Max;
if (CurrentGragh.Net_Graph[i][j].BandWidth_Max != 0) LineNum++;
}
SumLength[i][0] = Sum*LineNum;
SumLength[i][1] = i;
Sum = 0;
LineNum = 0;
for (int k = 0; k < SinglePointNum; k++)
{
if (i == ExpensePointID[SinglePoint[k]] - 1)
{
SumLength[i][0] = MaxERROR; //最大
SumLength[i][1] = i;
break;
}
}
}
MaoPao(SumLength, CurrentGragh.NetNodeNum);
for (int i = 0; i < CurrentGragh.NetNodeNum; i++)
{
PreSearchedPath[PreServerNum++] = SumLength[i][1];//保存第一次計算的路徑排序
NowSearchedPath[NowServerNum++] = SumLength[i][1];
//PRINT("到%d結點距離:%d\n", SumLength[i][1], SumLength[i][0]);
}
IsInited = true;
}
#endif // UsingRoom
}
/*********************************************
函數名:void MaoPao(unsigned short Point[Max_NetNodeNum][2], unsigned short PointNum)
函數功能:冒泡法排序
函數變量:Point[Max_NetNodeNum][2]:服務器數組,PointNum:普通節點點數
函數返回值:null
**********************************************/
void MaoPao(unsigned short Point[Max_NetNodeNum][2], unsigned short PointNum)
{
int i = 0, j = 0;
unsigned short Temp = 0;//存放最小值
unsigned short idTemp = 0;
for (i = 0; i < PointNum; i++)
{
for (j = i + 1; j < PointNum; j++)
{
#ifdef UsingDistance
if ((Point[i][0]>Point[j][0]) && (IsUsingRoom == false))
{
Temp = Point[i][0];
Point[i][0] = Point[j][0];
Point[j][0] = Temp;
idTemp = Point[i][1];
Point[i][1] = Point[j][1];
Point[j][1] = idTemp;
}
#endif // UsingDistance
#ifdef UsingRoom
if ((Point[i][0]<Point[j][0]) && (IsUsingRoom == true))
{
Temp = Point[i][0];
Point[i][0] = Point[j][0];
Point[j][0] = Temp;
idTemp = Point[i][1];
Point[i][1] = Point[j][1];
Point[j][1] = idTemp;
}
#endif // UsingDistance
}
}
}
/*********************************************
函數名:unsigned short GetMinFlow(unsigned short StartPoint, unsigned short EndPoint)
函數功能:計算最短距離裏面的最小流量
函數變量:Start_Point:初始點服務器,EndPoint終止點消費節點 0-N
函數返回值:最短距離帶寬
**********************************************/
unsigned short GetMinFlow(unsigned short StartPoint, unsigned short expenseID)
{
unsigned short MinFlow = MaxERROR; //表示最小流量
unsigned short PreID = ExpensePointID[expenseID] - 1; //鏈接的前一個點
unsigned short NowID = ExpensePointID[expenseID] - 1; //當前點
Path_Num[expenseID][1] = 0;//路徑清零
while (NowID != StartPoint) //搜尋到初始點爲止
{
PreID = ConnectedMin_ID[StartPoint][NowID];
if (MinFlow > CurrentGragh.Net_Graph[PreID][NowID].BandWidth_Max)//當前最小帶寬
MinFlow = CurrentGragh.Net_Graph[PreID][NowID].BandWidth_Max;
Path[expenseID][Path_Num[expenseID][0]][Path_Num[expenseID][1]++] = PreID; //記錄路徑
NowID = PreID; //循環賦值
}
Path[expenseID][Path_Num[expenseID][0]][Path_Num[expenseID][1]++] = -1;//路徑結束標誌
return MinFlow;
}
/*********************************************
函數名:unsigned short UpdateGraph(unsigned short MinFlow, unsigned short serverID, unsigned short expenseID)
函數功能:更新圖表並計算
函數變量:MinFlow:路徑上最小帶寬,serverID: 服務器地址 expenseID:消費節點編號 0-N
函數返回值:最短距離帶寬
**********************************************/
unsigned short UpdateGraph(unsigned short MinFlow, unsigned short serverID, unsigned short expenseID)
{
unsigned short needBandWidth = 0;
unsigned short sendBandWidth = 0;
unsigned short PreID = ExpensePointID[expenseID] - 1; //鏈接的前一個點
unsigned short NowID = ExpensePointID[expenseID] - 1; //當前點
bool IsNeedRefresh = false;
needBandWidth = CurrentGragh.Net_Graph[CurrentGragh.NetNodeNum + expenseID][ExpensePointID[expenseID] - 1].BandWidth_Need - CurrentGragh.Net_Graph[expenseID][ExpensePointID[expenseID] - 1].SatisfiedBandWidth;
if (needBandWidth > MinFlow)//比較最大傳輸帶寬和需要帶寬大小
sendBandWidth = MinFlow;
else
sendBandWidth = needBandWidth;
PathExpense[expenseID][Path_Num[expenseID][0]] = sendBandWidth;//記錄該路徑上的帶寬
if (sendBandWidth!=0) Path_Num[expenseID][0]++;//路徑條數++
else return sendBandWidth;
while (NowID != serverID) //搜尋到初始點爲止
{
PreID = ConnectedMin_ID[serverID][NowID];
CurrentGragh.Net_Graph[PreID][NowID].BandWidth_Max = CurrentGragh.Net_Graph[PreID][NowID].BandWidth_Max - sendBandWidth;//更新網絡節點剩餘帶寬
if (CurrentGragh.Net_Graph[PreID][NowID].BandWidth_Max == 0)
{
IsNeedRefresh = true;
}
NowID = PreID; //循環賦值
}
if (IsNeedRefresh == true) UpdateServerAll(NowServerNum);// 更新服務器
CurrentGragh.Net_Graph[CurrentGragh.NetNodeNum + expenseID][ExpensePointID[expenseID] - 1].BandWidth_Need -= sendBandWidth;//更新消費節點需要帶寬
return sendBandWidth;
}
/*********************************************
函數名:void UpdateServerAll(unsigned short ServerNum)
函數功能:更新所有服務器與網絡鏈接關係
函數變量:ServerNum:服務器個數
函數返回值:最短距離帶寬
**********************************************/
void UpdateServerAll(unsigned short ServerNum)
{
for (int i = 0; i < CurrentGragh.ExpenseNum; i++)
UpdateSinggleServer(NowServerNum, i);
}
void UpdateSinggleServer(unsigned short ServerNum, unsigned short SingleExpensePoint)
{
unsigned short Connect_Min = MaxERROR; //定義與某一點相連的路徑最小值
unsigned short Current_Aspect = 0; //當前層,或者與當前尋找的次數
unsigned short Current_Point = 0; //當前點
unsigned short SameLegthNum = 0; //當前層找到的最小路徑數量
unsigned short i = 0;
unsigned short Sum_Legtgh = 0; //累計長度
unsigned short LastNum = 1; //一共找到的點數
unsigned short Start_Point = ExpensePointID[SingleExpensePoint] - 1;
unsigned short PreID = 0, NowID = 0;
unsigned short PaiXuNum = 0;
memset(SearchedPoint, 0, Max_NetNodeNum*sizeof(unsigned short));
LastPoint[0] = Start_Point; //第一次賦值
for (int n = 0; n < NowServerNum; n++) //服務器和消費節點直接相連
{
if (Start_Point == NowSearchedPath[n])
{
ExpenceClosedServer[SingleExpensePoint][0] = 0; //記錄離消費節點最近的服務器距離
ExpenceClosedServer[SingleExpensePoint][1] = NowSearchedPath[n]; //記錄離消費節點最近的服務器編號
return;
}
}
for (Current_Aspect = 0; Current_Aspect < CurrentGragh.NetNodeNum; Current_Aspect++) //表示是第幾次尋找
{
for (int n = 0; n < LastNum; n++)
{
Current_Point = LastPoint[n];
if ((SearchedPoint[Current_Point] != 0) || (Current_Point == Start_Point)) //此點已經存在,即已經被搜尋過
{
for (int k = 0; k < ConnectNum[Current_Point]; k++)
{
i = ConnectRelation[Current_Point][k];
if ((i != Start_Point) && (Connect_Min >= SearchedPoint[Current_Point] + CurrentGragh.Net_Graph[i][Current_Point].SingleCost) && (CurrentGragh.Net_Graph[i][Current_Point].BandWidth_Max != 0) && (SearchedPoint[i] == 0)) //找到這一層的最小值
{
if (Connect_Min>SearchedPoint[Current_Point] + CurrentGragh.Net_Graph[i][Current_Point].SingleCost) //最小值更新
{
SameLegthNum = 0;
}
Connect_Min = SearchedPoint[Current_Point] + CurrentGragh.Net_Graph[i][Current_Point].SingleCost; //當前最小值
ConnectedNum_Pre[SameLegthNum][0] = Current_Point; //記錄被搜的編號
ConnectedNum_Pre[SameLegthNum][1] = i; //記錄搜到最小值的編號
SameLegthPoint[SameLegthNum++] = i; //記錄最小值個數以及座標
}
}
}
}
if (SameLegthNum == 0) break; //沒有找到點,退出搜索
else //尋找有沒有相同的終點,有的話,走路徑最短的那一條
{
unsigned short RepeatNum = 0; //重複的個數
memset(RepeatBuf, 0, Max_NetNodeNum*sizeof(unsigned short));
unsigned short MaxFlow = 0, MaxFlowPoint = 0;
for (int i = 0; (i < SameLegthNum); i++) //第幾個點
{
MaxFlow = CurrentGragh.Net_Graph[SameLegthPoint[i]][ConnectedNum_Pre[i][0]].BandWidth_Max;
MaxFlowPoint = ConnectedNum_Pre[i][0];
RepeatNum = 1; RepeatBuf[0] = i;
for (int j = i + 1; (j < SameLegthNum) && (j != i); j++)
{
if (SameLegthPoint[i] == SameLegthPoint[j]) //兩個點是同一個點
{
if (CurrentGragh.Net_Graph[SameLegthPoint[j]][ConnectedNum_Pre[j][0]].BandWidth_Max > MaxFlow)
{
MaxFlow = CurrentGragh.Net_Graph[SearchedPoint[j]][ConnectedNum_Pre[j][0]].BandWidth_Max;
MaxFlowPoint = ConnectedNum_Pre[j][0];
}
RepeatBuf[RepeatNum++] = j;//第幾個點
}
}
for (int k = 0; k < RepeatNum; k++)
{
ConnectedNum_Pre[RepeatBuf[k]][0] = MaxFlowPoint;
ConnectedNum_Pre[RepeatBuf[k]][1] = SameLegthPoint[i];
}
}
}
for (i = 0; i < SameLegthNum; i++)
{
SearchedPoint[SameLegthPoint[i]] = Connect_Min; //放入最短長度
ConnectedLength_Min[SameLegthPoint[i]][Start_Point] = Connect_Min; //最小距離放入鏈接數組
ConnectedMin_ID_Test[Start_Point][ConnectedNum_Pre[i][1]] = ConnectedNum_Pre[i][0];
LastPoint[LastNum++] = SameLegthPoint[i]; //記錄已經被找過的點數
for (int n = 0; n < NowServerNum; n++)
{
if (SameLegthPoint[i] == NowSearchedPath[n]) //找到最近的服務器
{
PreID = Start_Point; NowID = NowSearchedPath[n];
ExpenceClosedServer[SingleExpensePoint][0] = Connect_Min; //記錄離消費節點最近的服務器距離
ExpenceClosedServer[SingleExpensePoint][1] = NowSearchedPath[n]; //記錄離消費節點最近的服務器編號
while (NowID != Start_Point)
{
NowID = ConnectedMin_ID_Test[Start_Point][NowID];
PaiXu[PaiXuNum++] = NowID;
}
NowID = Start_Point;
while (PaiXuNum > 1)
{
ConnectedMin_ID[NowSearchedPath[n]][NowID] = PaiXu[PaiXuNum - 2];
NowID = PaiXu[PaiXuNum - 2];
PaiXuNum--;
}
ConnectedMin_ID[NowSearchedPath[n]][NowID] = NowSearchedPath[n];
return;
}
}
}
SameLegthNum = 0; Connect_Min = MaxERROR; PaiXuNum = 0; //累計清零
}
}
/*********************************************
函數名:void SatifyPoint(unsigned short expenseID, unsigned short servernumed)
函數功能:滿足特定消費節點需要
函數變量:servernumed:服務器個數 expenseID:消費節點標號 0-N
函數返回值:null
**********************************************/
void SatifyPoint(unsigned short expenseID, unsigned short servernumed)
{
unsigned short serverID = 0;
unsigned short MiniFlow = 0;
static unsigned short temp = 0;
while (CurrentGragh.Net_Graph[CurrentGragh.NetNodeNum + expenseID][ExpensePointID[expenseID] - 1].BandWidth_Need != 0)//判斷當前節點是否被滿足
{
if (temp == CurrentGragh.Net_Graph[CurrentGragh.NetNodeNum + expenseID][ExpensePointID[expenseID] - 1].BandWidth_Need)
{
UnsatifiedPoint[UnsatifiedNum++] = expenseID;
break;
}
temp = CurrentGragh.Net_Graph[CurrentGragh.NetNodeNum + expenseID][ExpensePointID[expenseID] - 1].BandWidth_Need;
serverID = MinPoint(servernumed, ExpensePointID[expenseID] - 1); //獲得最短路徑的服務器編號
MiniFlow = GetMinFlow(serverID, expenseID); //獲得改路徑上的最小帶寬
UpdateGraph(MiniFlow, serverID, expenseID); //滿足更新
NetPathALL++; //路徑累計
}
}
/*********************************************
函數名:unsigned short GetCharge(void)
函數功能:獲得所有費用
函數變量:void
函數返回值:null
**********************************************/
unsigned long GetCharge(char * TextFile, bool IsPrint)
{
unsigned long ChargeALL_Temp = 0;
unsigned short PreID = 0;
unsigned short NowID = 0;
ChargeALL_Temp += NowServerNum*CurrentGragh.ServerCost;//獲得服務器費用
if (IsPrint == true) PRINT("總條數:%d\n", NetPathALL);
for (int i = 0; i < CurrentGragh.ExpenseNum; i++) //消費節點
{
for (int j = 0; j < Path_Num[i][0]; j++) //消費節點邊數
{
PreID = ExpensePointID[i] - 1;//消費節點ID
if (IsPrint == true) PRINT("%d ", i);
if (IsPrint == true) PRINT("%d ", PreID);
for (int k = 0; Path[i][j][k] != -1; k++)
{
NowID = Path[i][j][k];
ChargeALL_Temp += CurrentGragh.Net_Graph[NowID][PreID].SingleCost*PathExpense[i][j];
PreID = NowID;
if (IsPrint == true) PRINT("%d ", Path[i][j][k]);
}
if (IsPrint == true) PRINT("流量:%d\n", PathExpense[i][j]);
}
}
if (IsPrint == true) PRINT("總費用:%d\n", ChargeALL_Temp);
return ChargeALL_Temp;
}
/*********************************************
函數名:void UpdateMaxie(void)
函數功能:更新矩陣
函數變量:void
函數返回值:null
**********************************************/
void UpdateMaxie(void)
{
int i = 0, j = 0;
for (i = 0; i < CurrentGragh.ExpenseNum + CurrentGragh.NetNodeNum; i++)
{
if (i < CurrentGragh.ExpenseNum) { Path_Num[i][0] = 0; Path_Num[i][1] = 0; }//路徑數和路徑上點數清零
for (j = 0; j < CurrentGragh.ExpenseNum + CurrentGragh.NetNodeNum; j++)
{
ConnectedLength_Min[i][j] = ConnectedLength_Min_Temp[i][j];
ConnectedMin_ID[i][j] = ConnectedMin_ID_Temp[i][j];
}
}
for (i = 0; i < BandWidthNum; i++)
{
CurrentGragh.Net_Graph[BandWidth[i][0]][BandWidth[i][1]].BandWidth_Max = BandWidth[i][2];
CurrentGragh.Net_Graph[BandWidth[i][1]][BandWidth[i][0]].BandWidth_Max = BandWidth[i][2];
CurrentGragh.Net_Graph[BandWidth[i][0]][BandWidth[i][1]].SingleCost = BandWidth[i][3];
CurrentGragh.Net_Graph[BandWidth[i][1]][BandWidth[i][0]].SingleCost = BandWidth[i][3];
}
for (i = 0; i < CurrentGragh.ExpenseNum; i++)
{
CurrentGragh.Net_Graph[CurrentGragh.NetNodeNum + i][ExpensePointID[i] - 1].BandWidth_Need = ExpenseBandNeed[i];
CurrentGragh.Net_Graph[ExpensePointID[i] - 1][CurrentGragh.NetNodeNum + i].BandWidth_Need = ExpenseBandNeed[i];
}
}
/*********************************************
函數名:void GetMaxFlow(void)
函數功能:獲得最大流量和最小費用
函數變量:void
函數返回值:null
**********************************************/
unsigned short SameLengthBuf[Max_NetNodeNum] = { 0 };
bool GetMaxFlow(void)
{
unsigned long MaxFlowALL = 0;
unsigned short MinPath = MaxERROR;
unsigned short MinPathTemp = MaxERROR;
unsigned short ServerID = 0, ExpenseID = 0;
unsigned long CurrentFlow = 0;
unsigned long SumFlow = 0;
unsigned long PreSumFlow = 0;
unsigned long MaxFlow = 0;
unsigned long MaxFlowTemp = 0;
unsigned short SameLengthNum = 0;//相同長度累計
NetPathALL = 0;//所有路徑清零
for (int i = 0; i < CurrentGragh.ExpenseNum; i++) MaxFlowALL += CurrentGragh.Net_Graph[i + CurrentGragh.NetNodeNum][ExpensePointID[i] - 1].BandWidth_Need;
while (SumFlow != MaxFlowALL)
{
MinPath = MaxERROR;
for (int i = 0; i < CurrentGragh.ExpenseNum; i++) //找到最短路徑和編號
{
MinPathTemp = ConnectedLength_Min[ExpenceClosedServer[i][1]][ExpensePointID[i] - 1]; //消費節點到服務器最短路徑
if ((MinPathTemp <= MinPath) && (CurrentGragh.Net_Graph[CurrentGragh.NetNodeNum + i][ExpensePointID[i] - 1].BandWidth_Need != 0))
{
if (MinPathTemp < MinPath) SameLengthNum = 0;
MinPath = MinPathTemp;//賦值
ServerID = ExpenceClosedServer[i][1]; ExpenseID = i; //保存服務器編號和消費節點編號0-N
SameLengthBuf[SameLengthNum++] = i;
}
}
MaxFlow = 0; MaxFlowTemp = 0;
for (int k = 0; k < SameLengthNum; k++) //在最短路徑中選擇流量量大或最小
{
unsigned short i = SameLengthBuf[k];
if ((ExpenceClosedServer[i][0] == MinPath) && (CurrentGragh.Net_Graph[CurrentGragh.NetNodeNum + i][ExpensePointID[i] - 1].BandWidth_Need != 0)) //是最短路徑時
{
MaxFlowTemp = GetMinFlow(ExpenceClosedServer[i][1], i); //獲取最近的服務器流量
if (MaxFlowTemp != MaxERROR)
{
if (MaxFlowTemp>CurrentGragh.Net_Graph[CurrentGragh.NetNodeNum + i][ExpensePointID[i] - 1].BandWidth_Need)
MaxFlowTemp = CurrentGragh.Net_Graph[CurrentGragh.NetNodeNum + i][ExpensePointID[i] - 1].BandWidth_Need;
}
if ((MaxFlowTemp > MaxFlow) && (MaxFlowTemp != MaxERROR) && (MaxFlowTemp != 0))
{
MaxFlow = MaxFlowTemp;
ServerID = ExpenceClosedServer[i][1]; ExpenseID = i;//保存服務器編號和消費節點編號0-N
}
}
}
//PRINT("路徑服務器%d,消費節點%d\n", ServerID, ExpenseID);
if (MinPath != MaxERROR)
{
CurrentFlow = GetMinFlow(ServerID, ExpenseID); //獲得改路徑上的最小帶寬
CurrentFlow = UpdateGraph(CurrentFlow, ServerID, ExpenseID); //滿足更新
if (CurrentFlow != 0) NetPathALL++; //路徑累計
//CurrentFlow=UpdateGraph(CurrentFlow, ServerID, ExpenseID);
SumFlow += CurrentFlow;//當前累計流量
if (SumFlow == PreSumFlow) { return false; }
PreSumFlow = SumFlow;
}
}
return true;
}
/*********************************************
函數名:void GetSinglePoint(void)
函數功能:獲得系統中的孤立節點
函數變量:void
函數返回值:null
**********************************************/
unsigned short CurrentBuf[Max_NetNodeNum][2] = { 0 };
void GetSinglePoint(void)
{
memset(CurrentBuf, 0, 2*Max_NetNodeNum*sizeof(unsigned short));
for (int i = 0; i < CurrentGragh.ExpenseNum; i++) //當鏈接的消費節點線路的流量*單位費用>一個服務器單價的時候,直接放一個服務器在該消費節點
{
unsigned long ChargeExpense = 0; //當前花費
unsigned short CurrentFlow = 0; //當前流量
unsigned short CurrentNeed = CurrentGragh.Net_Graph[i + CurrentGragh.NetNodeNum][ExpensePointID[i] - 1].BandWidth_Need; //當前需要流量
unsigned short CurentTemp = 0;
for (int j = 0; j < ConnectNum[ExpensePointID[i] - 1]; j++) //當前所有連接的消費節點
{
CurrentBuf[j][0] = CurrentGragh.Net_Graph[ExpensePointID[i] - 1][ConnectRelation[ExpensePointID[i] - 1][j]].SingleCost;
CurrentBuf[j][1] = ConnectRelation[ExpensePointID[i] - 1][j];
}
//MaoPao(CurrentBuf, ConnectNum[ExpensePointID[i] - 1],);//路徑,單價從小到大排序\
//冒泡法start
int ii, jj;
unsigned short Temp = 0;//存放最小值
unsigned short idTemp = 0;
for (ii = 0; ii < ConnectNum[ExpensePointID[i] - 1]; ii++)
{
for (jj = ii + 1; jj < ConnectNum[ExpensePointID[i] - 1]; jj++)
{
if ((CurrentBuf[ii][0]>CurrentBuf[jj][0]))
{
Temp = CurrentBuf[ii][0];
CurrentBuf[ii][0] = CurrentBuf[jj][0];
CurrentBuf[jj][0] = Temp;
idTemp = CurrentBuf[ii][1];
CurrentBuf[ii][1] = CurrentBuf[jj][1];
CurrentBuf[jj][1] = idTemp;
}
}
}
//冒泡法End
for (int j = 0; j < ConnectNum[ExpensePointID[i] - 1]; j++) //排序後得到最短錢數
{
if (CurrentFlow < CurrentGragh.Net_Graph[i + CurrentGragh.NetNodeNum][ExpensePointID[i] - 1].BandWidth_Need)
{
CurentTemp = (CurrentGragh.Net_Graph[ExpensePointID[i] - 1][CurrentBuf[j][1]].BandWidth_Max> CurrentNeed) ? CurrentNeed : CurrentGragh.Net_Graph[ExpensePointID[i] - 1][CurrentBuf[j][1]].BandWidth_Max;
CurrentFlow += CurentTemp;
ChargeExpense += CurentTemp*CurrentGragh.Net_Graph[ExpensePointID[i] - 1][CurrentBuf[j][1]].SingleCost;
CurrentNeed -= CurentTemp;
}
}
if ((ChargeExpense > CurrentGragh.ServerCost) || (CurrentFlow<CurrentGragh.Net_Graph[i + CurrentGragh.NetNodeNum][ExpensePointID[i] - 1].BandWidth_Need))
{
SinglePoint[SinglePointNum++] = i;//放入孤立節點,直接把服務器放在這
}
}
}
void DivisionBlock(void)
{
unsigned short TempPoint = 0;
unsigned short TempNumExpense = 0;
unsigned short TempNumNode = 0;
unsigned short temp = 0;
int k = 0;
for (int i = 0; i < CurrentGragh.ExpenseNum; i++) //遍歷每個消費節點
{
TempPoint = ExpensePointID[i] - 1;
ConnectedNodePoint[i][TempNumExpense++] = TempPoint; //把與消費節點綁定的普通節點記錄下來
ConnectedExpensePoint[TempPoint][ConnectedExpensePointNum[TempPoint]++] = i; //把普通節點與哪些消費節點有關係記錄下來
for (int j = 0; j < 2; j++) //每個消費節點遍歷深度爲2
{
for (k = 0; k < CurrentGragh.NetNodeNum; k++)
{
if (CurrentGragh.Net_Graph[TempPoint][k].BandWidth_Max != 0)
{
ConnectedNodePoint[i][TempNumExpense++] = k;
ConnectedExpensePoint[k][ConnectedExpensePointNum[k]++] = i;
}
}
TempPoint = k;
}
ConnectedNodePointNum[i] = TempNumExpense;
//ConnectedExpensePointNum[]
TempNumExpense = 0;
TempNumNode = 0;
}
/*上面把消費節點遍歷了一遍*/
/*下面的部分爲劃分成不同的小塊*/
PreServerNum = 0; NowServerNum = 0;
/*得到每個普通節點與其他節點的大概關係*/
for (int j = 0; j < CurrentGragh.NetNodeNum; j++)
{
if (ConnectedExpensePointNum[j] != 0)
{
for (int p = 0; p < ConnectedExpensePointNum[j]; p++)
{
temp += ConnectedNodePointNum[ConnectedExpensePoint[j][p]];
}
}
NodeNum[j][0] = temp;
NodeNum[j][1] = j;
temp = 0;
}
int i = 0, j = 0;
unsigned short Temp = 0;//存放最小值
unsigned short idTemp = 0;
for (i = 0; i < CurrentGragh.NetNodeNum; i++)
{
for (j = i + 1; j < CurrentGragh.NetNodeNum; j++)
{
if (NodeNum[i][0] < NodeNum[j][0])
{
Temp = NodeNum[i][0];
NodeNum[i][0] = NodeNum[j][0];
NodeNum[j][0] = Temp;
idTemp = NodeNum[i][1];
NodeNum[i][1] = NodeNum[j][1];
NodeNum[j][1] = idTemp;
}
}
}
}
/*********************************************
函數名:void GetExpenseMin(void)
函數功能:獲得系統中的消費節點最短距離
函數變量:void
函數返回值:null
**********************************************/
void GetExpenseMin(void)
{
short i = 0, j = 0;
short MinLength = MaxERROR;//最小距離
short CurrentID = MaxERROR;
memset(ExpensePointSum, 0, Max_NetNodeNum * 2 * sizeof(unsigned short));
for (i = 0; i < CurrentGragh.ExpenseNum; i++) //當前消費節點
{
MinLength = MaxERROR; CurrentID = MaxERROR;
for (j = 0; (j < CurrentGragh.ExpenseNum); j++) //與這比較的消費節點
{
if ((i != j) && (MinLength>ConnectedLength_Min[ExpensePointID[i] - 1][ExpensePointID[j] - 1]) && (ConnectedLength_Min[ExpensePointID[i] - 1][ExpensePointID[j] - 1] != 0))
{
MinLength = ConnectedLength_Min[ExpensePointID[i] - 1][ExpensePointID[j] - 1];
CurrentID = j;
}
}
if ((MinLength != 0) && (MinLength != MaxERROR))
{
unsigned short PreID = ExpensePointID[i] - 1; //鏈接的前一個點
unsigned short NowID = ExpensePointID[CurrentID] - 1; //當前點
ExpensePointSum[NowID][0]++;
ExpensePointSum[NowID][1] = NowID;
while (NowID != ExpensePointID[i] - 1) //搜尋到初始點爲止
{
PreID = ConnectedMin_ID[ExpensePointID[i] - 1][NowID];
NowID = PreID; //循環賦值
ExpensePointSum[NowID][0]++;
ExpensePointSum[NowID][1] = NowID;
}
}
}
//冒泡排序
unsigned short Temp = 0;//存放最小值
unsigned short idTemp = 0;
for (i = 0; i < CurrentGragh.NetNodeNum; i++)
{
for (j = i + 1; j < CurrentGragh.NetNodeNum; j++)
{
if ((ExpensePointSum[i][0]<ExpensePointSum[j][0]))
{
Temp = ExpensePointSum[i][0];
ExpensePointSum[i][0] = ExpensePointSum[j][0];
ExpensePointSum[j][0] = Temp;
idTemp = ExpensePointSum[i][1];
ExpensePointSum[i][1] = ExpensePointSum[j][1];
ExpensePointSum[j][1] = idTemp;
}
}
}
}