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

算法分析:

分析题目得,应当得到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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值