算法分析:
分析題目得,應當得到k個結點的dist數組,從這k個數組中可以得知,k個結點中的某個結點A到另一個結點B的路徑長度(這條路徑中間可能經過k個結點中的第三個結點,我們不去關心他,只抽象爲一條從結點A到結點B的一條通路)。之後對k個結點進行全排列決定信號的傳遞順序(同上,中間可能從A到B時經過C ,不關心這中間的C),然後計算path總長,對所有的順序序列進行搜索比較出最短的即可。
也即,此題的精髓便是k次Dijkstra(不用Floyd是因爲O(V3)的複雜度必超時)+枚舉搜索(path序列進行全排列)
Debug記錄:
見代碼註釋
題目
題目描述
網絡的高效互聯與智能傳輸是提升海量用戶服務請求映射效率的重要措施。在這個任務中,你要用最少的傳輸時間,將特定的數據源發送到指定的網絡節點中。
我麼給定的網絡一共包含N個節點(從1到N編號),其中節點1爲數據源。網絡中有M條無向邊(u,v,w),表示一條傳輸線連接節點u和節點v,且數據通過這條傳輸線的平均時間爲w。由於傳送機制的限制,當一個節點接收到數據之後,它只能選擇與它互連的一個節點,並將數據轉發到該節點。節點1在初始化時只會發送一次數據,但在傳輸過程中它可以作爲轉發節點。
網絡中有k個目標節點,你需要計算出該數據從節點1傳送到所有K歌節點所需要的最短時間。注意目標節點可以按任意順序進行傳送,數據也可以多次經過同一節點。
輸入格式
輸入數據第一行是一個整數T(T<=5),表示測試數據的組數。
對於每組測試數據:
第一行是三個正整數N,M,K(2<=N<=1000,1<=M<=N(N-1)/2,K<=10),分別表示節點數,邊數和目標節點數。
接下來M行,每行三個整數u,v,w(1<=u,v<=N, 0<=w<=1000,u!=v)。如上所述給出每條傳輸線。任意兩個網絡節點之間最多隻會有一條邊相連。
最後一行是K個整數,給出所有的目標節點的編號,所有目標節點的編號都在2到N之間。
輸出格式
對於每組測試數據,輸出數據傳送到所有K個目標節點的最短時間。
樣例輸入
2
3 2 2
1 3 1
1 2 3
2 3
6 6 4
1 5 1
5 6 2
2 1 20
2 3 5
3 4 5
6 3 1
2 3 4 6
樣例輸出
5
19
樣例說明
在第一組樣例中,最短路線是:1->3->1->2
在第二組樣例中,最短路線是:1->5->6->3->2->3->4,或者1->5->6->3->4->3->2
//適用於有向圖
//若是無向圖,將/*無向圖*/處註釋取消即可
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#define MAXSIZE 1010
#define INF 0x7fffffff
using namespace std;
struct Edge{
int end;
double weight;
Edge(){
}
Edge(int end,double weight){
this->end=end;
this->weight=weight;
}
bool operator<(const Edge e){//useless
return weight<e.weight;
}
};
struct Graph{ //頂點下標從0開始
int graphSize;
vector<Edge> edge[MAXSIZE];//edgeList
int dist[MAXSIZE][MAXSIZE];
int initGraph(int graphSize){
this->graphSize=graphSize;
for (int i=0;i<graphSize;i++)
edge[i].clear();
//以下對dist[]的初始化可能帶來大量的時間開銷 ,若不需要請刪除或簡化
for (int i=0;i<graphSize;i++){
for (int j=0;j<graphSize;j++){
dist[i][j]=-1;
}
}
for (int i=0;i<graphSize;i++){
dist[i][i]=0;
}
}
void Dijkstra(int origin){
//declare
bool mark[MAXSIZE];
int newPoint,minDistVex;
int temp;
//initiate
for (int i=0;i<graphSize;i++){
mark[i]=false;
dist[origin][i]=-1;
}
newPoint=origin; //originate x 求x結點到其他所有結點的最短路徑
mark[newPoint]=true;
dist[origin][newPoint]=0;
//process
for (int time=0;time<graphSize-1;time++){//每趟循環找出x到一個結點的最短路徑,共n-1趟
//遍歷newPoint直接相鄰的結點,修改其dist
for (int i=0;i<edge[newPoint].size();i++){
int end=edge[newPoint][i].end;
if (mark[end]==true)//if end結點已經在x集合中,則跳過此次循環
continue;
temp=dist[origin][newPoint]+edge[newPoint][i].weight;
if (temp<dist[origin][end]||dist[origin][end]==-1) //if the new dist< the old dist
dist[origin][end]=temp;
}
//遍歷dist,從mark爲false的結點中找出其dist最小的結點,確定爲新的newPoint,並加入x集合
int i;
for (i=0;i<graphSize;i++){//initiate minDistVex
if (mark[i]==false&&dist[origin][i]!=-1){
minDistVex=i;
break;
}
}
for (i++;i<graphSize;i++){
if (mark[i]==false&&dist[origin][i]!=-1&&dist[origin][i]<dist[origin][minDistVex])
minDistVex=i;
}
newPoint=minDistVex;
mark[minDistVex]=true;
}
}
};
int main(){
int t,n,m,k;//求origin到各節點的dist
Graph graph;
int origin,start,end,weight;
int path[10];
int tempPath,shortestPath;
cin>>t;
while (t--){//n vexes ,m edges
//initiate
cin>>n>>m>>k;
origin=0;//當題設的結點下標從0開始時,做調整
graph.initGraph(n);
//input edge
for (int i=0;i<m;i++){
cin>>start>>end>>weight;
start--;end--;//當題設的結點下標從0開始時,做調整
graph.edge[start].push_back(Edge(end,weight));
graph.edge[end].push_back(Edge(start,weight));
}
for (int i=0;i<k;i++){
cin>>path[i];
path[i]--;//adjust
}
sort(path,path+k);
//Dijkstra
graph.Dijkstra(0);/*忘記做0結點的Dijkstra*/
for (int i=0;i<k;i++){
graph.Dijkstra(path[i]);
}
//cal
shortestPath=INF;
do{
tempPath=graph.dist[0][path[0]];
if (tempPath==-1)
continue;//tempPath=INF,即進入下一趟while
for (int i=0;i<k-1;i++){
if (graph.dist[path[i]][path[i+1]]==-1){
tempPath=INF;/*bug:沒有考慮到此路不通的情況*/
break;
}
tempPath+=graph.dist[path[i]][path[i+1]];
}
//debug
// cout<<tempPath<<endl;
//*****
if (tempPath<shortestPath){
shortestPath=tempPath;
}
} while (next_permutation(path,path+k));
//output
cout<<shortestPath<<endl;
}
return true;
}