比賽從3.3日開始,但是其實3.2日賽題已經出來了,那天下午在實驗室同學的提醒下就下載了賽題,然后花了好久才看懂是什么東西。開始真是一頭霧水,看群里有人說是最大流問題,然后就想到看的算法導論里面第26章,然后就自然想到了最小費用最大流問題,也算是幸運,在這個上面沒花什么時間。
3.2日晚上想了好久,想到了一個思路,就是把所有消費節點直連的網絡節點都放置服務器,然后再刪服務器,然后像中間靠攏,后面可以嘗試一些啟發式。然后就嗨了,,,結果第二天小原的介紹賽題的視頻里面直接就說了直連,讓我感覺前天晚上白想了,真是笑哭了。
有了思路后就是擼代碼了,花了一點時間把項目轉到vs上面,然后讀取數據,直連,我的第一版就這么產生了,從5號晚上開始,花了整整一天時間來上傳,才成功,原因是跟去年的不一樣,去年直接編譯直接提交壓縮包就行了,今年得自己壓縮,,,真是心累啊!
當時還是西北賽區第一個提交成功的人,然后也保持了很久的第一,這個還是讓我比較開心的一件事,至少我擼代碼速度還是比較快的。但是從第一開始往后掉的感受真心虐。
這里有個小插曲,開始的時候官網的評分機制是有問題的,給出來的case都比較小,我用的同學的一個小號程序員鼓勵師就這么在第一的位置持續了十來天左右,蘭大的哥們應該到現在也不知道他們前面的第一是個小號吧!不過這也是讓蘭大的哥們一直優化的動力啊,哈哈。
有了直連版本,后面的就好說了,費用流開始用的是SPFA,對開始的小case,還是可以滿足的,然后就寫了刪點,相鄰結點交換,度最高的點交換(度定義的是每個節點輸出帶寬/帶寬費用),然后就靠這個稱了幾天,直到8號左右開始第一保不住了,然后就慌了,覺得必須得上點啟發式了,然后就花了兩天時間改了我的第一版遺傳。
第一版遺傳的效果特別渣,可以說根本就沒什么效果,有的case都沒有直連效果好,現在時間有點長了,具體bug忘記了,但是當時記得是一個很搞笑的bug。
后來很長一段時間都沒有什么進展,然后到了28號左右的時候,SPFA已經明顯跟不上節奏了,必須得換其他算法了,就花了兩天時間改了ZKW算法,這個算法真是厲害,因為里面里面包含了一個反向邊的概念,之前一直沒有搞懂這個,所有一直沒有看懂,所以也一直沒有用,換了zkw之后,遺傳對中小case可以達到最優了,但是對高級還是不行,因為我的初始解太大了(初賽的初始解都是隨機的,現在想想能撐到復賽也是心累),高級我用的還是最初的那個刪點+相鄰結點交換+度高的交換。
最后最終case出來的時候,我還能保持在十來名左右,所以也就有點放松心態了,沒怎么優化了,但是最后一天直接從14名掉到33名,真嚇尿了,然后又花了點時間優化下提交了,刷到前面去了,最后初賽結束,保住了32強,最后是31名,現在想想真是驚險。
最后總結一下,這個比賽真心累,但是也會讓人上癮,因為花一個月時間認真去干一件事情確實收獲很大,比賽過程中確實也學到了很多東西。
發現當時比賽的時候有好多話想說,結果拖到現在全忘了,就這樣吧,哈哈!
初賽代碼還有很多問題,比如遺傳交叉其實作用不大,但是我每次遺傳的時候交叉計算一次cost,然后變異計算一次cost,浪費了大把時間;
然后初始解也有問題,我遺傳的初始解是隨機的,這樣的話初始解cost就很大,所以當時高級case一直降不下去就是因為這個原因,在復賽的時候解決了
update函數是開始給一個直連解,然后刪服務器,度比較好的交換,相鄰結點交換,都是貪心的,
#include "deploy.h" #include <stdio.h> #include <memory.h> #include <stdlib.h> #include <time.h> #include <math.h> #include <queue> #include "timerclock.h" #include <vector> #include <iostream> using namespace std; std::time_t Timer::_time_start; #define SUM 6 //總共的染色體數量 #define MAXLOOP 10000 //遺傳最大循環次數 #define OUTLOOP 10000 //多少次最優解不變退出 #define maxcrossp 0.8 //交叉概率 #define maxmp 0.9 //變異概率 #define mincrossp 0.3 //最小交叉概率 #define minmp 0.00001 //最小變異概率 #define NUMEDGE 30000 //原圖的最大邊數 const int MAXN = 1510; const int MAXM = 40000000; const int INF = 1000000000; const int S = 1501; const int T = 1502; int result_unchange_time; //記錄在error前提下最優值未改變的循環次數 int NE; //邊的數量 int head[MAXN]; //以某一個結點為起頭的是那一條邊 int dist[MAXN]; //存儲到源點s的距離 int pp[MAXN]; //存儲前驅頂點 int numserver = 0; //服務器數量 int numedge = 0; //邊數 int numnode = 0; //結點數 int numcons = 0; //消費結點數 int servercost = 0; //安裝每台服務器花費 //int path[1000][100]; //輸出路徑時記錄路徑 char ret[40000]; //保存輸出字符串 bool vis[MAXN]; //訪問標記 int MIN_COST; int relasum[1000]; //按出度分割的數組,用於初始化解 vector<vector<int>> retpath; vector<int > tempway; vector<int > costway; /*******************************結點的度排序結構**************************************/ struct node{// float sum; //每個網絡節點的單位價錢出度 bool havedep;//是否放置了服務器 }point[MAXN]; /*******************************圖的鄰接表表示****************************************/ struct Edge { int u; int v; int cap; int cost; int next; }edge[NUMEDGE],incomedge[MAXM]; /***************************************基因結構體************************************/ struct gen{ bool info[1000]; //染色體結構,用一個數組作為染色體編碼 int cost; //此染色體結構的花費 float fitfx; }; struct gen gen_group[SUM]; //定義一個含有20個染色體的組 struct gen gen_new[SUM]; //交叉變異產生的新染色體 struct gen gen_result; //記錄最優的染色體 /**************************************基礎函數聲明**********************************/ void recover(); void init(); void ways(int f,int u); void reading(char * topo[MAX_EDGE_NUM]); //讀取數據 void addedge(int u,int v,int cap,int cost); //個位的0、1代表一對正反向的邊 void deledge(int u,int v); //個位的0、1代表一對正反向的邊 void character(int temp,int& i); //輸出數字轉換成char數組 int getcost(int ans); char* output(); int relativerand(int *div ,int left, int right); //按相對權值返回一個隨機值 bool insertserver(int i); bool isright(); int randbit(int i,int j); //產生一個在i,j兩個數之間的隨機整數 int randsign(float p); //按概率p返回1 void delser(int aaa); /**************************************遺傳操作聲明**********************************/ void initiate(); //初始化函數,主要負責產生初始化種群 void delser2(); //刪除初始解中沒有用的網絡節點 void optimi( int flag ); //評估種群中各染色體的適應度,並據此進行排序 void gen_swap(gen *a,gen *b); //結構體交換 void gen_quicksort(gen *number,int left,int right); //種群排序 void cross(int n); //交叉函數 void selection(); //輪盤賭選擇函數 void selection1(); //快速選擇函數 void mutation(int n); //變異函數 int record(int n); //記錄每次循環產生的最優解並判斷是否終止循環 int ANS,TEMPCOST; //返回的總cost int aug (int u,int f) { if (u == T) { ANS+=TEMPCOST*f; return f; } vis[u]=true; int tmp=f; for (int i=head[u]; i!=-1; i=incomedge[i].next){ if (incomedge[i].cap && !incomedge[i].cost && !vis[incomedge[i].v]) { int delta = aug(incomedge[i].v, tmp < incomedge[i].cap ? tmp : incomedge[i].cap); incomedge[i].cap -= delta; incomedge[i^1].cap += delta; tmp -= delta; if (!tmp) return f; } } return f-tmp; } bool modlabel() { for(int i = 0; i < MAXN; i++) dist[i] = INF; dist[T] = 0; deque<int>Q; Q.push_back(T); while(!Q.empty()) { int u = Q.front(), tmp; Q.pop_front(); for(int i = head[u]; i != -1; i = incomedge[i].next) if(incomedge[i^1].cap && (tmp = dist[u] - incomedge[i].cost) < dist[incomedge[i].v]) (dist[incomedge[i].v] = tmp) <= dist[Q.empty() ? S : Q.front()] ? Q.push_front(incomedge[i].v) : Q.push_back(incomedge[i].v); } for(int u = 0; u < MAXN; u++) for(int i = head[u]; i != -1; i = incomedge[i].next) incomedge[i].cost += dist[incomedge[i].v] - dist[u]; TEMPCOST += dist[S]; return dist[S] < INF; } void ZKW() { ANS=TEMPCOST=0; while(modlabel()) { do { memset(vis, 0, sizeof(vis)); }while(aug(S, INF)); } } bool Update3(){ int cost=MIN_COST; //刪除某一服務器,是否可行 int jj=head[T]; while(jj!=-1&& !Timer::timeout()){ deledge(T,incomedge[jj].v); numserver--; recover(); ZKW(); int coss=getcost(ANS); if(isright()&&coss<MIN_COST){ MIN_COST=coss; point[incomedge[jj].v].havedep=false; } else{ addedge(incomedge[jj].v,T,INF,0); numserver++; } jj=incomedge[jj].next; recover(); } //度排序后從大到小替換 jj=head[T]; while(jj!=-1&& !Timer::timeout()){ int dey=0; while(point[dey].havedep){ ++dey; } for(int i=dey+1;i<numnode;++i){ if(point[i].havedep==false&&point[i].sum>point[dey].sum){ dey=i; } } deledge(T,incomedge[jj].v); addedge(dey,T,INF,0); recover(); ZKW(); int coss=getcost(ANS); if(isright()&&coss<MIN_COST){ MIN_COST=coss; point[dey].havedep=true; point[incomedge[jj].v].havedep=false; jj=incomedge[jj].next; continue; } else{ deledge(T,dey); addedge(incomedge[jj].v,T,INF,0); recover(); } jj=incomedge[jj].next; } //鄰域替換 int ptredge=head[T]; while(ptredge!=-1&& !Timer::timeout()){ int nextedge=head[incomedge[ptredge].v]; while(nextedge!=-1){ if(incomedge[nextedge].v!=T){ deledge(T,incomedge[ptredge].v); addedge(incomedge[nextedge].v,T,INF,0); recover(); ZKW(); int coss=getcost(ANS); if(isright()&&coss<MIN_COST){ MIN_COST=coss; point[incomedge[nextedge].v].havedep=true; point[incomedge[ptredge].v].havedep=false; break; } else{ deledge(T,incomedge[nextedge].v); addedge(incomedge[ptredge].v,T,INF,0); recover(); } } nextedge=incomedge[nextedge].next; } ptredge=incomedge[ptredge].next; } if(cost>MIN_COST)return true; else return false; } void deploy_server(char * topo[MAX_EDGE_NUM], int line_num,char * filename){ Timer::tic(); int i; result_unchange_time = 0; gen_result.cost = INF; init(); reading(topo); if(numnode<600){ srand((unsigned)time(NULL)); //srand(1); initiate(); //產生初始化種群,未經優化的初始種群 optimi( 0 ); //對父種群進行優化,評分,排序 MIN_COST = INF; for(i = 0; i < MAXLOOP && !Timer::timeout(); ++i){ cross(i); optimi(1); if(record(i) == 1){ break; } selection(); mutation(i); optimi(0); if(gen_group[0].cost > gen_result.cost){ //精英保留 gen_group[SUM-1].cost = gen_result.cost; for(int k = 0; k < numnode ; ++k){ gen_group[SUM-1].info[k] = gen_result.info[k]; } } } printf("迭代次數:%d\n\n",i); int ptr = head[T]; while(ptr != -1){ deledge( T , incomedge[ptr].v ); ptr = incomedge[ptr].next; } numserver=0; //把最優的染色體染色體中的服務器裝配上 for(int z=0;z<numnode;++z){ if(gen_result.info[z]==1){ addedge(z,T,INF,0); numserver++; } } }else{ numserver=numcons; MIN_COST=INF; int loop = 6; while(loop>=0){ Update3(); loop--; } } recover(); ZKW(); i = head[S]; while(i != -1){ ways(edge[i].cap , edge[i].v); i = edge[i].next; } char *topo_file=output(); //printf("%s\n",topo_file); printf("zkw計算總花費為:%d\n",getcost(ANS)); write_result(topo_file, filename); }void selection(){ //輪盤賭 int i , j , k; int min = INF, max = 0; for(i = 0; i < SUM; ++i){ if(min>gen_group[i].cost){ min = gen_group[i].cost; } else if(max < gen_group[i].cost && gen_group[i].cost != INF){ max = gen_group[i].cost; } if(min>gen_new[i].cost){ min = gen_new[i].cost; } else if(max < gen_new[i].cost && gen_new[i].cost != INF){ max = gen_new[i].cost; } } float diff = (float)max - min; for(i = 0; i < SUM; ++i){ if(gen_group[i].cost == INF){ gen_group[i].fitfx = 0; } else{ float temp = (gen_group[i].cost - min + diff)/diff; gen_group[i].fitfx = 1.0/(pow(temp,13)); } if(gen_new[i].cost == INF){ gen_new[i].fitfx = 0; } else{ float temp = (gen_new[i].cost - min + diff)/diff; gen_new[i].fitfx = 1.0/(pow(temp,13)); } } float sum = 0.0; //適應度函數求和 for(i = 0; i < SUM ; ++i){ sum += gen_group[i].fitfx + gen_new[i].fitfx; } int relfitfx[SUM * 2]; //相對適應度分配 relfitfx[0] = 0; for(i = 1; i < SUM ; ++i){ relfitfx[i] = relfitfx[i-1] + 32768 * gen_group[i].fitfx/sum; } for(i = 0; i < SUM ; ++i){ relfitfx[SUM+i] = relfitfx[SUM+i-1] + 32768 * gen_new[i].fitfx/sum; } bool temp[SUM * 2]; //保存該個體是否選擇 memset(temp,false,sizeof(temp)); int loop = 0; i = 0; while(loop < SUM && i<2000){ //如果2000次沒有選足下一代,就退出 int tt = relativerand(relfitfx ,0 ,SUM*2-1); if(!temp[tt]){ temp[tt] = true; ++loop; } ++i; } j = 0; for(i = 0;i < SUM*2 -1 ;++i){ if(temp[i]){ if(i < SUM){ gen_group[j].cost = gen_group[i].cost; for(k = 0; k < numnode ; ++k){ gen_group[j].info[k] = gen_group[i].info[k]; } } else{ gen_group[j].cost = gen_new[i-SUM].cost; for(k = 0; k < numnode ; ++k){ gen_group[j].info[k] = gen_new[i-SUM].info[k]; } } ++j; } } } int record(int n){ int i; if( gen_group[0].cost < gen_result.cost && gen_group[0].cost < gen_new[0].cost){ for( i = 0; i < numnode; ++i ){ gen_result.info[i] = gen_group[0].info[i]; } gen_result.cost = gen_group[0].cost; result_unchange_time = 0; } else if(gen_new[0].cost < gen_result.cost){ for( i = 0; i < numnode; ++i ){ gen_result.info[i] = gen_new[0].info[i]; } gen_result.cost = gen_new[0].cost; result_unchange_time = 0; } else{ ++result_unchange_time; if( result_unchange_time >= OUTLOOP ){ return 1; } } return 0; } void mutation(int n){ int i, j; float gmp; gmp = 1 - pow( 1-maxmp , 11);//在基因變異概率為mp時整條染色體的變異概率 for(i = 0;i < SUM;++i){ if( randsign(gmp) == 1 ){//以gmp的概率返回1 j = randbit( 0 , numnode-1 ); if( gen_group[i].info[j] != 1 ){ gen_group[i].info[j] = 1; } else{ gen_group[i].info[j] = 0; } } } } void cross(int n){ int i , j , k ,z; int a[SUM]; for(i = 0 ; i < SUM ; i++) a[i] = 0; //將所有染色體設為沒有交叉 k = 0; for( i = 0; i < SUM ; ++i ){ if( a[i] == 0 ){ while( 1 ){ j = randbit( i+1 , SUM - 1 );//隨機選與i交叉染色體的位置 if( a[j] == 0 ) break; //如果該點沒有被交叉過,就break } if( randsign( maxcrossp ) == 1 ){ //按照crossp的概率對選擇的染色體進行交叉操作 int tem=randbit(0 , numnode-1); //隨機選交叉點的位置 for( z = 0; z < tem ; ++z){ gen_new[k].info[z] = gen_group[i].info[z]; gen_new[k+1].info[z] = gen_group[j].info[z]; } for( z = tem; z < numnode; ++z){ gen_new[k].info[z] = gen_group[j].info[z]; gen_new[k+1].info[z] = gen_group[i].info[z]; } gen_new[k].cost = INF; gen_new[k+1].cost = INF; } else{ gen_new[k].cost = gen_group[i].cost; gen_new[k+1].cost = gen_group[j].cost; for( z = 0;z < numnode; ++z){ gen_new[k].info[z] = gen_group[i].info[z]; gen_new[k+1].info[z] = gen_group[j].info[z]; } } a[i] = a[j] = 1; k +=2; } } } void optimi( int flag ){ int i, j, ptrhead; struct gen *genp; if( flag == 0) genp = gen_group; else genp = gen_new; for( i = 0; i < SUM; ++i ){ numserver=0; //把改染色體的服務器全連上 for( j = 0; j < numnode; ++j){ if( genp[i].info[j] ){ addedge( j, T, INF, 0 ); ++numserver; } } recover(); ZKW(); if( !isright() ){ //當該染色體不滿足消費節點的時候 genp[i].cost = INF; } else{ genp[i].cost = getcost(ANS); } //把所有服務器與匯點斷開 ptrhead = head[T]; while( ptrhead != -1 ){ deledge( T , incomedge[ptrhead].v ); //刪除與T相連的服務器 ptrhead = incomedge[ptrhead].next; } } gen_quicksort(genp,0,SUM-1); //對種群進行重新排序 } int relativerand(int *div ,int left, int right){ int randtemp = randbit(0 , 32768); int mid; while(left <= right){ mid = (left + right)/2; if(div[mid] < randtemp){ left = mid + 1; } else{ right = mid - 1; } } return right; } void delser2(){ recover(); ZKW(); int ptr = head[T]; while(ptr != -1){ //殘缺網絡上面該服務器與T之間的帶寬沒有變,表示該服務器沒有使用,則刪除 int nptr = head[incomedge[ptr].v]; while(nptr != -1){ if(incomedge[nptr].v == T && incomedge[nptr].cap == INF){ deledge( T, incomedge[ptr].v ); } nptr = incomedge[nptr].next; } ptr = incomedge[ptr].next; } } void initiate(){ int i ,j ,ptrT; //*************初始解0***********************************/ //因為在讀取數據是已經把服務器連接到消費節點直接相鄰的網絡節點上,所以現在直接讀取 for(i = 0; i < numnode ; ++i){ gen_group[0].info[i] = false; } gen_group[0].cost = INF; ptrT = head[T]; while(ptrT != -1){ gen_group[0].info[incomedge[ptrT].v] = true; deledge(T , incomedge[ptrT].v); ptrT = incomedge[ptrT].next; } //計算相對出度比例 float sum = 0; relasum[0] = 0; for(i = 0; i < numnode ; ++i){ sum += point[i].sum; } for(i = 1; i < numnode ; ++i){ //計算累計概率 relasum[i] = relasum[i-1] + 32768 * point[i].sum / sum; } //*************初始解1-SUM***********************************/ for(i = 1; i < SUM; ++i ){ for(j = 0; j < numnode ; ++j){ gen_group[i].info[j] = false; } gen_group[i].cost = INF; for(j=0;j<numnode;++j){ point[j].havedep = false; //將所有的點設為沒有設服務器 } j = 0; while(j < numcons){ //先隨機添加numserver個服務器 int tem = relativerand(relasum ,0 ,numnode - 1); if(!point[tem].havedep){ addedge(tem , T , INF , 0); point[tem].havedep=true; j++; } } recover(); while(!insertserver(relativerand(relasum ,0 ,numnode - 1))){ ; } delser2(); ptrT = head[T]; while(ptrT != -1){ gen_group[i].info[incomedge[ptrT].v] = true; deledge(T , incomedge[ptrT].v); ptrT = incomedge[ptrT].next; } } } bool insertserver(int i){ if(!point[i].havedep){//如果排序后第i小的某個網絡節點上沒有服務器 addedge(i , T , INF , 0); point[i].havedep=true;//排序后第i小的某個網絡節點上布置了服務器 recover(); ZKW(); } return isright(); } void gen_swap(gen *a,gen *b) { gen temp; temp = *a; *a = *b; *b = temp; } void gen_quicksort(gen *number,int left,int right)//快速排序,用於結構體排序 { int i,j,s; if(left<right) { s=number[(left+right)/2].cost,j=right+1,i=left-1; while(1) { while(number[++i].cost<s) ; while(number[--j].cost>s) ; if(i>=j) break; gen_swap(&number[i],&number[j]); } gen_quicksort(number,left,i-1); gen_quicksort(number,j+1,right); } } void reading(char * topo[MAX_EDGE_NUM]){ int temp[3]={0}; int i=0,k=0,j=0; while(topo[0][i]!='\n'){ if(topo[0][i]>='0'&&topo[0][i]<='9') temp[k]=temp[k]*10+topo[0][i]-'0'; else{ ++k; } ++i; } numnode=temp[0];numedge=temp[1];numcons=temp[2]; i=0; while(topo[2][i] != '\r'&&topo[2][i]!='\n'){ servercost=servercost*10+topo[2][i++]-'0'; } int link[4]; for(i=4;i<4+numedge;++i){ k=0;j=0;int tem=0; while(topo[i][k] != '\n'&&topo[i][k] != '\0'){ tem=tem*10+topo[i][k++]-'0'; if(topo[i][k]==' '||topo[i][k]=='\r'||topo[i][k] == '\n'){ link[j++]=tem; tem=0; k++; } } point[link[0]].sum+=(float)link[2]/link[3];//獲取網絡節點的度 point[link[1]].sum+=(float)link[2]/link[3]; addedge(link[0],link[1],link[2],link[3]); addedge(link[1],link[0],link[2],link[3]); } for(i=5+numedge;i<5+numedge+numcons;++i){ k=0;j=0;int tem=0; while(topo[i][k] != '\n'&&topo[i][k] != '\0'){ tem=tem*10+topo[i][k++]-'0'; if(topo[i][k]==' '||topo[i][k]=='\r'||topo[i][k] == '\n'){ link[j++]=tem; tem=0; k++; } } addedge(1000+link[0],link[1],link[2],0); addedge(S,1000+link[0],link[2],0); addedge(link[1],T,INF,0); //初始化服務器位置,為與消費節點相連的網絡結點 } } void deledge(int u,int v)//個位的0、1代表一對正反向的邊 { int i,j; i = head[u];//i為當前邊 j = incomedge[i].next;//j為當前邊的下一條邊; if(incomedge[i].v == v){ head[u] = incomedge[i].next; } else{ while(j != -1){ if(incomedge[j].v == v){ incomedge[i].next = incomedge[j].next; if(i<NUMEDGE && j <NUMEDGE){ edge[i].next = edge[j].next; } break; } i = incomedge[i].next; j = incomedge[j].next; } } i = head[v]; j = incomedge[i].next; if(incomedge[i].v == u){ head[v] = incomedge[i].next; } else{ while(j!=-1){ if(incomedge[j].v==u){ incomedge[i].next = incomedge[j].next; if(i<NUMEDGE && j <NUMEDGE){ edge[i].next = edge[j].next; } //edge[i].next = edge[j].next; break; } i = incomedge[i].next; j = incomedge[j].next; } } } void addedge(int u,int v,int cap,int cost) { if(NE < NUMEDGE){ edge[NE].u=u; edge[NE].v=v; edge[NE].cap=cap; edge[NE].cost=cost; edge[NE].next=head[u]; } incomedge[NE].u=u; incomedge[NE].v=v; incomedge[NE].cap=cap; incomedge[NE].cost=cost; incomedge[NE].next=head[u]; head[u]=NE++; if(NE < NUMEDGE){ edge[NE].u=v; edge[NE].v=u; edge[NE].cap=0; edge[NE].cost=-cost; edge[NE].next=head[v]; } incomedge[NE].u=v; incomedge[NE].v=u; incomedge[NE].cap=0; incomedge[NE].cost=-cost; incomedge[NE].next=head[v]; head[v]=NE++; } void init() { NE=0; memset(head,-1,sizeof(head)); } void character(int temp,int& i)//輸出數字轉換成char數組 { if(temp>=1000){ temp-=1000; character(temp,i); } else if(temp<=9&&temp>=0){ ret[i]=(char)temp+'0'; i++; return; } else{ char tem=(char)(temp%10)+'0'; character(temp/10,i); ret[i]=tem; i++; } } char* output(){ int ptrret = 0;//定位字符位置 character(retpath.size() , ptrret); ret[ptrret] = '\n'; ptrret++; ret[ptrret] = '\n'; ptrret++; int m = retpath.size(); for(int ii = 0; ii < m ; ++ii){ int n = retpath[ii].size()-1; for(int jj=n ;jj >= 0; --jj){ character(retpath[ii][jj],ptrret); ret[ptrret] = ' '; ptrret++; } character(costway[ii],ptrret); ret[ptrret]='\n'; ptrret++; } ret[ptrret-1]='\0'; return ret; } void ways(int f,int u){ if(f == 0){ return; } else{ int ptr = head[u]; while(ptr != -1){ if(incomedge[ptr].v == T){ tempway.push_back(u); retpath.push_back(tempway); tempway.pop_back(); costway.push_back(f); return; } else if( f>0 && edge[ptr].cap > 0){ //如果是正向邊 int temp=edge[ptr].cap-incomedge[ptr].cap; //求出該路徑上流過的流量 temp = temp > f ? f : temp; tempway.push_back(u); ways(temp , incomedge[ptr].v); tempway.pop_back(); incomedge[ptr].cap += temp; incomedge[ptr^1].cap -= temp; f -= temp; } ptr = incomedge[ptr].next; } } } int getcost(int ans){//獲取目前安置服務器的費用 return servercost*numserver+ans; } void recover(){ for(int i=0;i<NUMEDGE;++i){ incomedge[i].cap=edge[i].cap; incomedge[i].cost=edge[i].cost; } } bool isright(){//最大流是否將每個消費節點與網絡節點的連線帶寬為零 int i; i=head[S]; while(i!=-1){ int j=head[incomedge[i].v]; while(j!=-1){ if(incomedge[j].v!=S){ if(incomedge[j].cap!=0){ return false; } } j=incomedge[j].next; } i=incomedge[i].next; } return true; } int randbit(int i, int j)//產生在i與j之間的一個隨機數 { int a , l; l = j - i + 1; a = i + rand()%l; return a; } int randsign(float p)//按概率p返回1 { if( (rand()%32768) > (p * 32768))//windows上面RAND_MAX是32768 return 0; else return 1; }