您的位置:首页 > 理论基础 > 计算机网络

北邮OJ-269. 网络传输-14网研上机D

2017-03-21 17:58 363 查看

算法分析:

分析题目得,应当得到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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息