1.1 最小費用最大流
今年的華為軟體精英挑戰賽是要在一張給定的流量網路中,找到合適伺服器部署地點、最佳路由路徑使得伺服器到達消費節點的費用在滿足流量需求的時候費用最小。因而在伺服器給定的情況下就變成了,最小費用最大流問題了。
首先最小費用
最大流問題:
已知容量網路d=(v,a,c),每條弧(vi,vj)
除了已給出容量cij
外,還給出了單位流量的傳輸費用bij
≥0,記作d=(v,a,c,b),其中bij
∈b。要在費用、容量網路d中尋找vs—>vt
的最大流f
,且使流的總傳輸費用最小:
對於最大流問題:
最大流的求法就是在容量網路上從某個可行流出發,設法找到一條從vs—>vt的增廣鏈,然後沿著此增廣鏈調整流量,作出新的流量增大了的可行流。在這個新的可行流基礎上再尋找它的增廣鏈。如此反覆進行,直至再找不出增廣鏈時,就得到了該網路的最大流。
最小費用最大流問題:
就先找乙個最小費用可行流,再找出關於該可行流的最小費用增廣鏈,沿此鏈調整流量,則得到乙個新的流量增大了的最小費用流,然後對新的最小費用流重複上述方法,一直調整到網路的最大流出現為止,便得到了所考慮網路的最小費用最大流。
具體的原理性說明可以參考這裡。
1.2 最短路演算法
最短路演算法在本賽題中占有至關重要的作用,演算法執行的效率和速度對比賽成績影響很大。(對於網路節點數目為800的圖在我的本子上要跑200多ms,但是大佬寫的借鑑zkw的最短路演算法,效率不知道高多少倍去了-_-||)。
spfa演算法估計是使用得比較多的方法了。spfa的原理其實與dijkstra原理上相似。只是它使用了乙個佇列去維護搜尋最短路,減少了冗餘。具體的原理的話這裡就不再多贅述。
網路圖資料結構:
#define max_net_node 1000 //最大網路節點
#define max_client_node 500 //最大消費節點
//網路中的網路節點的輸入和輸出節點
struct node
;node net_node[max_net_node]; //網路節點的儲存
//網路中的消費節點的輸入和頻寬需求
struct client_node
;client_node client_node[max_client_node]; //消費節點的儲存
int client_innode[max_net_node]; //儲存與消費節點相連的節點
int note_to_client[max_net_node]; //根據與消費節點相連的節點找到消費節點
int needed_flow=0; //在本case中需要的總流量
//每條邊的屬性:總頻寬,頻寬**
struct edge_atrribute
;edge_atrribute net_edge[max_net_node][max_net_node]; //儲存圖資料的矩陣
最小費用最大流(mcmf)(新增了slf和lll(-_-||)):
#define infinite 1 << 26
#define max_node 1005
//#define max_edge_num 40005
struct edge;
edge gedges[max_edge_num];
int ghead[max_node]; //
int gpre[max_node]; //
int gpath[max_node]; //路徑
int gdist[max_node]; //距離
int gedgecount;
*最小費用最大流 start*/
void my_search_init(std::vectorserver_pos)
for(unsigned int j=0; j" << temp_end << " , " << bandwidth << " , " << cost << endl;
cout << temp_end << "*****=>" << temp_start << " , " << bandwidth << " , " << cost << endl;
edge_count++;
edge_count++;
#endif
insertedge(temp_start, temp_end, bandwidth, cost);
insertedge(temp_end, temp_start, bandwidth, cost);
}#ifdef mydebug
cout << "伺服器節點:" << i << endl;
#endif
continue;
} for(unsigned int j=0; j" << (temp_end) << " , " << bandwidth << " , " << cost << endl;
cout << temp_end << "*****=>" << temp_start << " , " << bandwidth << " , " << cost << endl;
edge_count++;
edge_count++;
#endif
insertedge(temp_start, temp_end, bandwidth, cost);
insertedge(temp_end, temp_start, bandwidth, cost);
} }//加入超級起點節點的邊
#ifdef mydebug
cout << "超級起點節點的邊初始化:" << endl;
#endif
for(unsigned int i=0; i" << temp_end << " , " << needed_flow << " , " << 0 << endl;
edge_count++;
#endif
insertedge(start, temp_end, maxint, 0);
} //加入超級終點節點的邊
#ifdef mydebug
cout << "超級終點節點的邊初始化:" << endl;
#endif
for(int i=0; i" << end << " , " << bandwidth << " , " << 0 << endl;
edge_count++;
#endif
insertedge(temp_start, end, bandwidth, 0);
}#ifdef mydebug
cout << "加入的總邊數:" << edge_count << endl;
#endif
}bool checkisserver(int node_id, std::vectorserver_pos)
//找到增益的最小流
//cout << "increaseed flow:" << f << endl;
temp_path.push_back(f);
flow += f;
int temp = cost;
//cost += gdist[t] * f;
for (int u = t; u != s; u = gpre[u])
//設定路中的容量變化
temp_path.push_back(cost-temp); //記錄這條路的**
path.push_back(temp_path);
if(flow >= needed_flow) //找到需要的流量就可以了,不用找完所有的曾廣路線
return cost;
}return cost;
}//假設圖中不存在負權和環,spfa演算法找到最短路徑/從源點s到終點t所經過邊的cost之和最小的路徑
bool spfa(int s, int t)
bool isfind = false; //是否找到元素的標誌位
gdist[s] = 0;
//int sum(0); //lll中計算總的和的變數
std::dequeq;
q.push_back(s);
while (!q.empty())
//else
//}if (isfind)
for (int e = ghead[u]; e != -1; e = gedges[e].next)
else
}else
if (v == t)}}
}if (gpre[t] == -1) //若終點t沒有設定pre,說明不存在到達終點t的路徑
return false;
return true;
}//加入邊
void insertedge(int u, int v, int vol, int cost)
/*最小費用最大流 end*//
最小費用最大流
網 絡流的基本問題為 設乙個有向賦權圖g v,e v 其中有兩個特殊的節點s和s s稱為發點,s 稱為收點。圖中各 邊的方向和權數表示允許的流向和最大可能的流量 容量 問在這個網路圖中從發點流出到收點匯集,最大可通過的實際流量為多少?流向的分布情況為怎樣?設有乙個網路圖g v,e v e中的每條邊 ...
最小費用最大流
const int maxn 250 const int maxm 62272 const int inf 0x4ffffff int n,m struct edge edge maxm int head maxn cnt void init void addedge int u,int v,int...
最小費用最大流
看了最小費用最大流的問題,感覺好難啊,想不到,關鍵就是想不到,知道模板什麼用,只是能a題僅此而已,要想學深真的不是件容易的事情啊。為此我總結了以下幾點供複習知識點或者是講課時用 網路流的費用 在實際應用中,與網路流有關的問題,不僅涉及流量,而且還有費用的因素。網路的每一條邊 v,w 除了給定容量ca...