中興算法大賽


由華為軟件大賽得出的結論,比賽真的很重要,要不然一些機會就會失之交臂,所以抓緊參加了中興舉報的算法大賽,大賽的成績終於定下來了,出乎意料的低,35分連評語都沒有,雖然大家都在群里諷刺中興算法大賽是程序員營銷大賽,評分只看PPT,不過還是有很多可以總結的地方。

賽題為:

最強大腦中的收官蜂巢迷宮變態級挑戰,相信大家都嘆為觀止!最強大腦收官戰打響后,收視率節節攀升,就連蟻后也不時出題難為一下她的子民們。在動物世界中,稱得上活地圖的,除了蜜蜂,螞蟻當仁不讓。在復雜多變的蟻巢中, 螞蟻總是能以最快、最高效的方式游歷在各個儲藏間(存儲食物)。今天,她看完最新一期節目,又發布了一項新任務:小蟻同學,我需要玉米庫的玉米,再要配點水果,去幫我找來吧。小蟻正准備出發,蟻后又說:哎呀,回來,我還沒說完呢,還有若干要求如下:

1.小蟻同學,你需要盡可能以最少的花費拿到食物(附件圖中路線上的數值表示每兩個儲物間的花費);

2.小蟻同學,你最多只能經過9個儲藏間拿到食物(包含起止兩個節點,多次通過同一節點按重復次數計算);

3.小蟻同學,你必須經過玉米間,水果間(附件圖中標綠色節點);

4.別忘了,食蟻獸也在路上活動呢,一旦與食蟻獸相遇,性命危矣!不過小蟻微信群公告已經公布了敵人信息(附件圖中標紅色路段);

5.最后,千萬別忘了,還有兩段路是必須經過的,那里有我准備的神秘禮物等着你呢(附件圖中標綠色路段)。

這下小蟻犯難了,這和它們平時找食物的集體活動規則不一樣嘛,看來這次需要單獨行動了。要怎么選路呢?小蟻經過一番苦思冥想,稿紙堆了一摞,啊,終於找到了!親愛的同學們,你們能否也設計一種通用的路徑搜索算法,來應對各種搜索限制條件,找到一條最優路徑,順利完成蟻后布置的任務呢?

注:

1、蟻巢,有若干個儲藏間(附件圖中圓圈表示),儲藏間之間有諸多路可以到達(各儲藏間拓撲圖見附件);

2、節點本身通行無花費;

3、該圖為無向圖,可以正反兩方向通行,兩方向都會計費,並且花費相同;

4、起止節點分別為附件圖中S點和E點。

5、最優路徑:即滿足限制條件的路徑。

由於成績未出,稍后還有決賽還不便公布自己的算法,先寫到這里吧

 

一、算法思路:

我們把題目看成旅行商問題,然后用遺傳算法求出最優解或者次優解。

二、模型建立

本題屬於單源單點間附加必經點、必經邊的問題,為將本題轉化為旅行商問題,加上還需一條從源點S到終點T的附加邊,該邊的花費為源點到終點的花費,然后將邊當做一條必經邊來處理。對於必經邊,采用將必經邊也處理成一個特殊的必經點的方法,該特殊必經點包含起點和終點。在染色體中只出現必經邊u-v上的一點,如果是u則代表從必經邊的u點進入,從v點出去;如果是v則代表從必經邊的v點進入,從u點出去,然后本題就可以轉化為存在一定數量必經點的旅行商問題。

     初始化:生成SUM個初始解,初始解1為貪心解,其余SUM-1個解均為隨機生成。貪心解的思想是,離源點S越近的必經點或必經邊,越先放進解中,如例圖,離遠點最近的是屬於必經邊2-4的點2,所以將必經點2放進初始解(隱含了2-4這條邊),接下來是點7,將其放進解中,然后是屬於必經邊(13-14)的點14,將點14放進初始解中(隱含了14-13這條邊),然后是點12,最后把終點T到源點S的邊放進去,生成第一個貪心的初始解,為2(4)-7-14(13)-12-17(0);其余SUM-1個初始解均為隨機生成必經點必在解中,必經邊中的一個點u在解中,隱含了u-v這條邊,例如:上節隨機初始化的另一組解4 13 12 7 17,其中點4代表路徑4-2,13代表路徑13-1417代表路徑17-0

個體評價:以貪心生成的解2(4)-7-14(13)-12-17(0)為例:染色體中第一個基因是點2,屬於必經邊,現加上邊2-4的權值,然后加上4到下一個結點7的權值;結點7不是必經邊,直接加上結點7到下一個點14的權值;結點14屬於必經邊,先加上14-13的權值,再加上結點13-12的權值;結點12不是必經邊,直接加上結點12到下一結點17(即終點)的權值;結點17屬於必經邊,先加上結點17到結點0(即源點)的權值,然后加上結點02的權值;然后最后減去源點到起點的權值,即為此路徑的花費,上述貪心解的花費為13

對於該染色體經歷的結點數量使用的方法是提前通過弗洛伊德算法得到的最短路徑信息得到所有必經點之間兩兩的最小花費經歷結點數,然后對某一必經點組合,只需要遍歷一遍所有節點然后加起來,就可以得到改染色體所經歷的結點數;

選擇運算:因為通過交叉得到的子代總是小於等於父代,所以這里直接選擇交叉變異產生的子代。

記錄最優:有兩個記錄最優的方面,一方面是記錄滿足結點數滿足最少結點要求的最優解,一個室結點數不滿足最少節點數的次優解;

交叉運算:選擇兩個參加交叉的染色體作為父代,例如:

A=2(4)-7-14(13)-12-17(0)

B=12-7-13(14)-4(2)-17(0)

染色體Acost13,染色體Bcost19;首先比較結點47的權值為3127之間的權值也為3;就以2(4)為頭結點,將初始解右轉動為(染色體B中沒有特殊節點2(4),但是因為24均屬於必經邊2-4,在此將染色體B中的4(2)替換成2(4)代表從2點進入,然后從4點出)

A=2(4)-7-14(13)-12-17(0)

B=2(4)-17(0)-12-7-13(14)

然后比較47的權值為3417的權值為4,所以就有:

A=*-7-14(13)-12-17(0)

B=*-7-13(14)-17(0)-12

由此規則計算可得:

O=2(4)-7-14(13)-12-17(0)

我們本來是2個不同的解,現在得到了一個比兩個解都優的解,總不能讓原來的兩個解都等於現在的這個局部最優解吧,這樣不利於下次交叉,我們可以用隨機旋轉的方法改變另外一個解的路徑:Rotate(q.info, NUMmustp, rand() % NUMmustp);

變異運算只需要在一個解中隨機的選擇兩個基因,然后交換它們即可。

 

三、算法實現結果分析

 

    讀圖(鄰接表),將食蟻獸所在的路徑花費設為0x3f3f3f,既不經過此路徑(剪枝)

 

1.弗洛伊德算法求取加權圖中多源點之間最短路徑

 

    因為后期需要大量計算最短路徑,選擇迪傑斯特拉只能求取單源單匯之間的最短路徑,多次調用的話時間消耗太大。所以這里使用弗洛伊德算法一次求取,后面直接調用。迪傑斯特拉算法復雜度為主要依賴於最小優先隊列的實現,使用簡單數組算法復雜度為OV^2),使用二叉堆可以優化到O(ElgV),使用斐波那契堆可以優化到O(VlgV+E);而弗洛伊德時間復雜度為O(N^3),空間復雜度為O(N^2)。當圖的規模比較大,並且必經點、必經邊比較多的話,使用弗洛伊德算法可以大規模減少時間

 

2.初始化初始種群

 

    第一個解為貪心求得,其余SUM個解為隨機生成;因為例圖里面的點比較少,所以使用貪心求取的路徑已經是局部最優了

 

3.遺傳全局優化

 

     因為圖比較小,通過貪心就直接獲得最優了,所以這里我統計了每一代所有染色體的權值和的平均,種群規模SUM10000,制成圖。從上圖可以看出來通過遺傳可以很快收斂到最優附近,然后利用遺傳的全局尋優能力尋找最優解

 

4.輸出

 

    針對題中所給用例,通過我們的解題算法,在滿足所有要求的情況下並未搜索一條最優的路徑,經統計每一代最終的平均花費是逐漸變小並最終穩定在13,最終輸出一組次優路徑,路徑為:0->2->4->5->6->7->8->14->13->12->16->17,經過12個點,花費為13

 

#include<stdio.h>
#include <stdlib.h>  
#include <memory.h>

#define MAXN 10000
#define INF 0x3f3f3f
#define SUM 10            //總共的染色體數量  
#define MAXloop 10000       //最大循環次數  
#define error 0.01        //若兩次最優值之差小於此數則認為結果沒有改變  
#define crossp 0.7        //交叉概率  
#define mp 0.1           //變異概率 

int numnode = 0;
int dis[MAXN][MAXN];
int pathmatirx[MAXN][MAXN];
int numofnodepath[MAXN][MAXN];
int S ;   //起點
int T ;   //終點
int mustp[MAXN];
int nummustp = 0;   //必經點的個數,必經邊算兩個必經點
int NUMmustp = 0;   //個體中的染色體個數

int ret[1000];
int ptri = 0;

struct gen                        //定義染色體結構  
{  
    int info[MAXN];               //染色體結構,表示從0開始經過這個染色體結構之后,到達T
    int cost;            //次染色體所對應的適應度函數值,在本題中為表達式的值  
	int numofnode;
}; 
struct gen gen_group[SUM];//定義一個含有20個染色體的組    
  
struct gen gen_result;     //記錄次優的染色體 
struct gen gen_result2;    //記錄最優的染色體 
int result_unchange_time; //記錄在error前提下最優值為改變的循環次數  

struct mustedge{
	bool flag;
	int u;
	int v;
}ismustedge[MAXN];


//**************************************普通函數聲明*****************************//
void reading();                            //讀圖
void floyd();                              //弗洛伊德求最短路徑
void init();                               //初始化
int   randsign(float p);    //按照概率p產生隨機數0、1,其值為1的概率為p   
int   randbit(int i,int j); //產生一個在i,j兩個數之間的隨機整數   
void findway( int a , int b );
int numofnode( int i , int j );

//**************************************遺傳函數聲明*****************************//
void gen_swap(gen *a,gen *b);                         //結構體交換
void gen_quicksort(gen *number,int left,int right);   //種群排序
void initiate();            //初始化函數,主要負責產生初始化種群   
void evaluation(int flag);  //評估種群中各染色體的適應度,並據此進行排序   
void Cross_group( gen &p, gen &q);               //交叉函數   
void selection();           //選擇函數   
int  record();              //記錄每次循環產生的最優解並判斷是否終止循環   
void Varation_group(gen group[]);            //變異函數   
int Search_son( int path[], int len, int city);
int Search_son1( int path[], int len, int city);
void Rotate(int path[],int len, int m);

void evaluation(int flag)  
{  
    int i , j , node1 , node2 ;  
    struct gen *genp;   
	genp = gen_group; 
    for(i = 0 ; i < SUM ; i++)//計算各染色體對應的表達式值  
    {  
		genp[i].cost = 0;
		int cost = 0;
		int num = 0;
		for( j = 0 ; j < NUMmustp - 1 ; ++j ){
			if( !ismustedge[genp[i].info[j]].flag ){
				node1 = genp[i].info[j];
				node2 = genp[i].info[j + 1];
				cost += dis[node1][node2];
				num += numofnodepath[node1][node2];
			}
			else{
				node1 = genp[i].info[j];
				node2 = ismustedge[genp[i].info[j]].v;
				cost += dis[node1][node2];
				node1 = genp[i].info[j + 1];
				cost += dis[node2][node1];
				num += 1;
				num += numofnodepath[node2][node1];
			}
		}
		if( !ismustedge[genp[i].info[NUMmustp - 1]].flag ){
			node1 = genp[i].info[NUMmustp - 1];
			node2 = genp[i].info[0];
			cost += dis[node1][node2];
			num += numofnodepath[node1][node2];
		}
		else{
			node1 = genp[i].info[NUMmustp - 1];
			node2 = ismustedge[genp[i].info[NUMmustp - 1]].v;
			cost += dis[node1][node2];
			node1 = genp[i].info[0];
			cost += dis[node2][node1];
			num += 1;
			num += numofnodepath[node2][node1];
		}
		cost -= dis[T][S];
        genp[i].cost = cost;
		genp[i].numofnode = num;
    }  
	gen_quicksort(genp ,0 ,SUM-1 );              //對種群進行重新排序
}  

void calnodenum(){
	int i , j;
	for(i = 0 ; i < nummustp ; i++) {
		for(j = 0 ; j < nummustp; j++ ) {
			if(mustp[i] == mustp[j]){
				numofnodepath[mustp[i]][mustp[j]] = 0;
			}
			else{
				numofnodepath[mustp[i]][mustp[j]] = numofnode(mustp[i] , mustp[j]);
			}
			/*if(i == j){
				numofnodepath[i][j] = 0;
			}
			else{
				numofnodepath[i][j] = numofnode(i , j);
			}*/
		}
	}
}

int main(){
	
	int i , j;
	reading();

	

	floyd();

	calnodenum();

	result_unchange_time = 0;
	gen_result.cost = INF;
	gen_result2.cost = INF;
	initiate();
	evaluation( 0 );        //對初始化種群進行評估、排序   
	for( i = 0 ; i < MAXloop && result_unchange_time < 10 ; i++ )  
	{  
		printf("第%d次迭代:",i);
		for(int  ii = 0 ; ii < SUM ; ++ii ){
			printf("染色體%d:    ",ii);
			for(j = 0 ; j < NUMmustp; ++j ){
				printf("%d ",gen_group[ii].info[j]);
			}
			printf("    花費為:%d,結點數為:%d\n",gen_group[ii].cost,gen_group[ii].numofnode);
		}printf("\n");
		float temp = 0;
		for (j = 0; j < SUM; j+= 1)   
		{  
			temp += gen_group[j].cost;  
		}  

		printf("本代平均花費為:%f\n",temp/SUM);

		printf("\n\n\n\n");
		if (gen_group[0].cost < gen_result.cost)   
        {  
			result_unchange_time = 0;
            memcpy(&gen_result, &gen_group[0], sizeof(gen));  
        }
		else{
			result_unchange_time++;
		}

		for( j = 0; j < SUM ; ++j){
			if(gen_group[j].numofnode <= 9 && gen_group[j].cost < gen_result2.cost){
				result_unchange_time = 0;
				memcpy(&gen_result2, &gen_group[0], sizeof(gen));
			}
		}

		for (j = 0; j < SUM / 2; j+= 1)   
		{  
			Cross_group(gen_group[j], gen_group[ SUM - j -1]);  
		}  
		evaluation( 0 );
		Varation_group(gen_group);
		evaluation( 0 );

	}

	if(gen_result2.cost != INF){
		printf("有最優解:\n");
		memcpy(&gen_result, &gen_result2, sizeof(gen));
	}
	else{
		printf("無最優解,輸出次優解:\n");
	}

	for(int ii=0;ii<NUMmustp - 1;ii++)  
	{  
		i = gen_result.info[ii];
		j = gen_result.info[ii+1];
		if(ismustedge[i].flag){
			//printf(",V%d,",i);
			ret[ptri++] = i;
			findway(ismustedge[i].v , j);
		}
		else
			findway(i , j);
	} 
	i = gen_result.info[NUMmustp-1];
	j = gen_result.info[0];
	if(ismustedge[i].flag){
		//printf(",V%d,",i);
		ret[ptri++] = i;
		findway(ismustedge[i].v , j);
	}
	else
		findway(i , j);
	//printf("\n");printf("\n");


	int pos1 = Search_son1( ret, ptri, S);
	Rotate(ret, ptri, pos1);
	for( i = 0 ; i < ptri ; ++i){
		printf("%d->",ret[i]);
	}
	printf("\n");
	system("pause");
	return 0;
}
int numofnode( int i , int j ){
	int k , retnum = 0;
	k=pathmatirx[i][j];                               //取路徑上Vi的后續Vk  
	if(k==-1)  
	{  
		printf("頂點%d 和 頂點%d 之間沒有路徑\n",i,j);//路徑不存在   
	}  
	else  
	{  
		retnum++;
		while(k!=j)  
		{                          
			retnum++;
			k=pathmatirx[k][j];                   //求路徑上下一頂點序號   
		}  
	} 
	return retnum;
}

void findway( int i , int j ){
	int k ;
	k=pathmatirx[i][j];                               //取路徑上Vi的后續Vk  
	if(k==-1)  
	{  
		printf("頂點%d 和 頂點%d 之間沒有路徑\n",i,j);//路徑不存在   
	}  
	else  
	{  
		ret[ptri++] = i;
		while(k!=j)  
		{                          
			ret[ptri++] = k;
			k=pathmatirx[k][j];                   //求路徑上下一頂點序號   
		}  
	}  
}

void Varation_group(gen group[])  
{  
    int i, j, k;  
    double temp;  
    //變異的數量,即,群體中的個體以PM的概率變異,變異概率不宜太大  
    int num = SUM * mp;  
  
    while (num--)   
    {  
        //確定發生變異的個體  
        k = rand() % SUM;  
  
        //確定發生變異的位  
        i = rand() % NUMmustp;  
        j = rand() % NUMmustp;  
  
        //exchange  
		temp  = group[k].info[i];  
        group[k].info[i] = group[k].info[j];   
        group[k].info[j] = temp;  
    }  
}  

int Search_son1( int path[], int len, int city)  
{  
    int i = 0;  
    for (i = 0; i < len; i++)   
    {  
        if (path[i] == city)   
        {  
            return i;  
        }
    }  
    return -1;  
}  

int Search_son( int path[], int len, int city)  
{  
    int i = 0;  
    for (i = 0; i < len; i++)   
    {  
        if (path[i] == city)   
        {  
            return i;  
        }
		else if( ismustedge[ city ].flag && ismustedge[ city ].v == path[i] ){
			path[i] = ismustedge[ path[i] ].v;
			return i;
		}
    }  
    return -1;  
}  

//reverse a array  
//it's a auxiliary function for Rotate()   
void Reverse(int path[], int b, int e)  
{  
    int temp;  
  
    while (b < e)   
    {  
        temp = path[b];   
        path[b] = path[e];  
        path[e] = temp;  
  
        b++;  
        e--;  
    }  
}  
  
  
//旋轉 m 位  
void Rotate(int path[],int len, int m)  
{  
    if( m < 0 )  
    {  
        return;  
    }  
    if (m > len)   
    {  
        m %= len;  
    }  
  
    Reverse(path, 0, m -1);  
    Reverse(path, m, len -1);  
    Reverse(path, 0, len -1);  
}  

void Cross_group( gen &p, gen &q)  
{  
	//for(int ii = 0 ; ii < NUMmustp ; ++ ii){
	//	printf("%d ",p.info[ii]);
	//}printf("\n");
	//for(int ii = 0 ; ii < NUMmustp ; ++ ii){
	//	printf("%d ",q.info[ii]);
	//}printf("\n");printf("\n");printf("\n");

    int i = 0;  
    int pos1, pos2;  
    int len = NUMmustp;  
    int first;  

	double len1 ,len2 ;
	if( ismustedge[ p.info[0] ].flag )
		len1 = dis[ismustedge[ p.info[0]].v][ p.info[1] ];  
	else
		len1 = dis[p.info[0] ][ p.info[1] ];  
	if( ismustedge[ q.info[0] ].flag )
		len2 = dis[ismustedge[ q.info[0]].v][ q.info[1] ];
	else
		len2 = dis[q.info[0] ][ q.info[1] ];  

    if (len1 <= len2)   
    {  
        first = p.info[0];  
    }  
    else  
    {  
        first = q.info[0];  
    }  
    pos1 = Search_son( p.info + i, len, first);  
    pos2 = Search_son( q.info + i, len, first);  
  
    Rotate(p.info + i, len, pos1);  
    Rotate(q.info + i, len, pos2);  

    while ( --len > 1)   
    { 
		i++;  
		int span1 , span2 ;

		int temp;
		if(ismustedge[ p.info[i - 1] ].flag){
			temp = ismustedge[ p.info[i - 1] ].v;
		}
		else{
			temp = p.info[i - 1];
		}
		span1 = dis[temp][ p.info[i] ];  

		if(ismustedge[ q.info[i - 1] ].flag){
			temp = ismustedge[ q.info[i - 1] ].v;
		}
		else{
			temp = q.info[i - 1];
		}
		span2 = dis[temp][ q.info[i] ];  

		if ( span1 <= span2 )  
		{  
			pos2 = Search_son( q.info + i, len, p.info[i]);  
			Rotate(q.info + i, len, pos2);  
		}  
		else  
		{  
			pos1 = Search_son( p.info + i, len, q.info[i]);  
			Rotate(p.info + i, len, pos1);  
		} 
	}  
	
    Rotate(q.info, NUMmustp, rand() % NUMmustp); 
}  





void initiate(){
	/*********第一個初始解定義為按離起點的距離的順序*********************/
	bool *flag = NULL;                                 //用於標記必經點中的某點是否被選進染色體中
	flag = (bool*)malloc(sizeof(bool) * nummustp);
	if(flag == NULL){
		printf("error initiate\n");  
        exit(1);  
	}
	for(int i = 0 ; i < nummustp; ++i )flag[i] = false;
	int i , j , z ;
	gen_group[0].info[NUMmustp - 1] = T ; flag[nummustp - 1] = true; flag[0] = true;
	for( i = 0 ; i < NUMmustp - 1 ; ++i ){
		int min = INF;int k = INF;
		for( j = 0 ; j < nummustp ; ++j ){
			if(!flag[j] && dis[S][mustp[j]] < min ){
				min = dis[S][mustp[j]];
				k = j;
			}
		}
		
		if(k != INF){
			if( !ismustedge[mustp[k]].flag ){     //如果是必經點
				gen_group[0].info[i] = mustp[k];
				flag[k] = true;
			}
			else{                                 //如果是必經邊
				gen_group[0].info[i] = mustp[k];
				flag[k] = true;
				for(z = 0 ; z < nummustp ; ++z ){
					if( mustp[z] == ismustedge[mustp[k]].v ){
						flag[z] = true;break;
					}
				}
			}
		}
		else{
			break;
		}
	}

	/*********隨機生成剩余初始解*********************/
	int k;
	for( i = 1 ; i < SUM ; ++i ){
		for(j = 0 ; j < nummustp; ++j )flag[j] = false;
		gen_group[i].info[NUMmustp - 1] = T; flag[0] = true; flag[nummustp - 1] = true;
		for(j = 0 ; j < NUMmustp - 1 ; ++j ){
			k = randbit(0 , nummustp-1);
			while( flag[k] ){
				k = randbit(0 , nummustp-1);
			}

			if( !ismustedge[mustp[k]].flag ){     //如果是必經點
				gen_group[i].info[j] = mustp[k];
				flag[k] = true;
			}
			else{                                 //如果是必經邊
				gen_group[i].info[j] = mustp[k];
				flag[k] = true;
				for(z = 0 ; z < nummustp ; ++z ){
					if( mustp[z] == ismustedge[mustp[k]].v ){
						flag[z] = true;break;
					}
				}
			}
		}
	}

	free(flag);
	flag = NULL;
}

void reading(){
	FILE *fp;  
    if(NULL == (fp = fopen("case0.txt", "r")))  
    {  
        printf("error reading\n");  
        exit(1);  
    }  

	S = 0; numnode = 0;
	char ch;  
    while( '\n' != (ch=fgetc(fp)) )  //總的點的個數
    {  
		numnode = numnode*10 + ch - '0';  
		//printf("%c", ch);  
    }  
	T = numnode - 1;
	//printf("起點為%d,終點為%d,結點數目為%d\n" , S, T, numnode);
  
	ch=fgetc(fp);

	nummustp = 0;
	memset(mustp,0,sizeof(mustp));
	mustp[++nummustp] = S;++NUMmustp;
	while( '\n' != (ch=fgetc(fp)) )    //讀取必經點
    {  
		if(ch == ' '){
			++nummustp;++NUMmustp;
		}
		else{
			mustp[nummustp] = mustp[nummustp]*10 + ch - '0';  
			//printf("%c", ch);  
		}
    } 

	ch=fgetc(fp);

	init();
	int temp[3] = {0,0,0} , j = 0;
	while( '\n' != (ch=fgetc(fp)) )    //讀取圖
    {  
		temp[0] = 0 ,temp[1] = 0 ,temp[2] = 0 , j = 0;
		while(ch != '\n'){
			if( ch == ' ' ){
				++j;
			}
			else{
				temp[j] = temp[j]*10 + ch - '0';
			}
			ch = fgetc(fp);
		}
		dis[temp[0]][temp[1]] = temp[2];
		dis[temp[1]][temp[0]] = temp[2];
		pathmatirx[temp[0]][temp[1]] = temp[0];
		pathmatirx[temp[1]][temp[0]] = temp[1];
    }  

	while( '\n' != (ch=fgetc(fp)) )   //必經邊的權值設為0
    {  
		temp[0] = 0 ,temp[1] = 0 ,temp[2] = 0 , j = 0;
		while(ch != '\n'){
			if( ch == ' ' ){
				++j;
			}
			else{
				temp[j] = temp[j]*10 + ch - '0';
			}
			ch = fgetc(fp);
		}
		mustp[++nummustp] = temp[0];
		mustp[++nummustp] = temp[1];
		++NUMmustp;
		ismustedge[temp[0]].flag = true;
		ismustedge[temp[0]].u = temp[0];
		ismustedge[temp[0]].v = temp[1];
		ismustedge[temp[1]].flag = true;
		ismustedge[temp[1]].u = temp[1];
		ismustedge[temp[1]].v = temp[0];
    }  

	while( '\n' != (ch=fgetc(fp)) )   //懲罰邊的權值設為INF
    {  
		temp[0] = 0 ,temp[1] = 0 ,temp[2] = 0 , j = 0;
		while(ch != '\n'){
			if( ch == ' ' ){
				++j;
			}
			else{
				temp[j] = temp[j]*10 + ch - '0';
			}
			ch = fgetc(fp);
		}
		dis[temp[0]][temp[1]] = INF;
		dis[temp[1]][temp[0]] = INF;
	} 
	++NUMmustp;
	mustp[++nummustp] = T;
	ismustedge[S].flag = true;
	ismustedge[S].u = S;
	ismustedge[S].v = T;
	ismustedge[T].flag = true;
	ismustedge[T].u = T;
	ismustedge[T].v = S;
	++nummustp;            //必經點的數量+1
	//printf("\n");
    fclose(fp); 
}

void floyd(){                                  //計算所有頂點到所有頂點的最短路徑
    int k , i , j;  

	for( i = 0 ; i <= numnode ; ++i ){
		for( j = 0 ; j <= numnode ; ++j ){
			if(dis[i][j] < INF)
				pathmatirx[i][j] = j;               //初始化路徑數組
			else
				pathmatirx[i][j] = -1;
		}
	}

    for(k = 0 ; k < numnode ; ++k )  
    {  
        for( i = 0 ; i < numnode ; ++i )  
        {  
            for( j = 0 ; j < numnode ; ++j )  
            {  
                if( dis[i][j] > dis[i][k] + dis[k][j] ) {  
					//如果經過下標為k頂點路徑比原兩點間路徑更短
                    dis[i][j] = dis[i][k] + dis[k][j];   //更新當前兩點間權值
					pathmatirx[i][j] = pathmatirx[i][k]; //路徑設置為經過下標為K的頂點
				}
            }  
        }  
    }  
}  

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 init(){
	int i , j ;
	for( i = 0 ; i <= numnode ; ++i ){
		for( j = 0 ; j <= numnode ; ++j ){
			//pathmatirx[i][j] = j;               //初始化路徑數組
			if(i == j ) dis[i][j] = 0;
			else dis[i][j] = INF;
		}
	}
	for(i = 0 ; i < MAXN ; ++i ){
		ismustedge[i].flag = false;
	}
}

int randsign(float p)//按概率p返回1  
{  
    if(rand() > (p * 32768))  
        return 0;  
    else return 1;  
}  
int randbit(int i, int j)//產生在i與j之間的一個隨機數  
{  
    int a , l;  
    l = j - i + 1;  
    a = i + rand() * l / 32768;  
    return a;  
}  

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM